aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-06-22 10:01:17 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2017-06-30 11:58:44 +0000
commit29e41a9ee61a05274f77f89e9ffd8875f90d3308 (patch)
tree7de81ef4ad3bb0b2b0cd3313ee4dd03a76e9c681 /src/qml/jit
parent3a9f4d3ae701c7119016a0bf8b4e65ceb17864b0 (diff)
Remove now unused files
Remove all files from the old compiler pipeline that are now unused. This includes the whole IR, JIT code generation, and the old Moth Isel. Change-Id: I50d06abfbcf0e9755a54ed94638f8bb74f9512b1 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/jit')
-rw-r--r--src/qml/jit/jit.pri22
-rw-r--r--src/qml/jit/qv4assembler.cpp726
-rw-r--r--src/qml/jit/qv4assembler_p.h1851
-rw-r--r--src/qml/jit/qv4binop.cpp665
-rw-r--r--src/qml/jit/qv4binop_p.h256
-rw-r--r--src/qml/jit/qv4isel_masm.cpp1688
-rw-r--r--src/qml/jit/qv4isel_masm_p.h319
-rw-r--r--src/qml/jit/qv4regalloc.cpp1971
-rw-r--r--src/qml/jit/qv4regalloc_p.h140
-rw-r--r--src/qml/jit/qv4registerinfo_p.h112
-rw-r--r--src/qml/jit/qv4targetplatform_p.h707
-rw-r--r--src/qml/jit/qv4unop.cpp166
-rw-r--r--src/qml/jit/qv4unop_p.h92
13 files changed, 0 insertions, 8715 deletions
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
deleted file mode 100644
index 7ea4e951d5..0000000000
--- a/src/qml/jit/jit.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-include(../../3rdparty/masm/masm-defs.pri)
-
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-HEADERS += \
- $$PWD/qv4assembler_p.h \
- $$PWD/qv4regalloc_p.h \
- $$PWD/qv4targetplatform_p.h \
- $$PWD/qv4isel_masm_p.h \
- $$PWD/qv4binop_p.h \
- $$PWD/qv4unop_p.h \
- $$PWD/qv4registerinfo_p.h
-
-SOURCES += \
- $$PWD/qv4assembler.cpp \
- $$PWD/qv4regalloc.cpp \
- $$PWD/qv4isel_masm.cpp \
- $$PWD/qv4binop.cpp \
- $$PWD/qv4unop.cpp \
-
-include(../../3rdparty/masm/masm.pri)
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
deleted file mode 100644
index d062f3bbb2..0000000000
--- a/src/qml/jit/qv4assembler.cpp
+++ /dev/null
@@ -1,726 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qv4isel_masm_p.h"
-#include "qv4runtime_p.h"
-#include "qv4ssa_p.h"
-#include "qv4regalloc_p.h"
-#include "qv4assembler_p.h"
-
-#include <assembler/LinkBuffer.h>
-#include <WTFStubs.h>
-
-#if !defined(V4_BOOTSTRAP)
-#include "qv4function_p.h"
-#endif
-
-#include <iostream>
-#include <QBuffer>
-#include <QCoreApplication>
-
-#if ENABLE(ASSEMBLER)
-
-#if USE(UDIS86)
-# include <udis86.h>
-#endif
-
-using namespace QV4;
-using namespace QV4::JIT;
-
-CompilationUnit::~CompilationUnit()
-{
-}
-
-#if !defined(V4_BOOTSTRAP)
-
-void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
-{
- runtimeFunctions.resize(data->functionTableSize);
- runtimeFunctions.fill(0);
- for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
-
- QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction,
- (ReturnedValue (*)(QV4::ExecutionEngine *, const uchar *)) codeRefs[i].code().executableAddress());
- runtimeFunctions[i] = runtimeFunction;
- }
-}
-
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
- JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
- JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
- codeRefs[i] = codeRef;
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
- if (showCode) {
- WTF::dataLogF("Mapped JIT code for %s\n", qPrintable(stringAt(compiledFunction->nameIndex)));
- disassemble(codeRef.code(), compiledFunction->codeSize, " ", WTF::dataFile());
- }
- }
-
- return true;
-}
-
-#endif // !defined(V4_BOOTSTRAP)
-
-void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
-{
- const int codeAlignment = 16;
- quint64 offset = WTF::roundUpToMultipleOf(codeAlignment, unit->unitSize);
- Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
- for (int i = 0; i < codeRefs.size(); ++i) {
- CompiledData::Function *compiledFunction = const_cast<CompiledData::Function *>(unit->functionAt(i));
- compiledFunction->codeOffset = offset;
- compiledFunction->codeSize = codeRefs.at(i).size();
- offset = WTF::roundUpToMultipleOf(codeAlignment, offset + compiledFunction->codeSize);
- }
-}
-
-bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString)
-{
- Q_ASSERT(device->pos() == unit->unitSize);
- Q_ASSERT(device->atEnd());
- Q_ASSERT(int(unit->functionTableSize) == codeRefs.size());
-
- QByteArray padding;
-
- for (int i = 0; i < codeRefs.size(); ++i) {
- const CompiledData::Function *compiledFunction = unit->functionAt(i);
-
- if (device->pos() > qint64(compiledFunction->codeOffset)) {
- *errorString = QStringLiteral("Invalid state of cache file to write.");
- return false;
- }
-
- const quint64 paddingSize = compiledFunction->codeOffset - device->pos();
- padding.fill(0, paddingSize);
- qint64 written = device->write(padding);
- if (written != padding.size()) {
- *errorString = device->errorString();
- return false;
- }
-
- const void *undecoratedCodePtr = codeRefs.at(i).code().dataLocation();
- written = device->write(reinterpret_cast<const char *>(undecoratedCodePtr), compiledFunction->codeSize);
- if (written != qint64(compiledFunction->codeSize)) {
- *errorString = device->errorString();
- return false;
- }
- }
- return true;
-}
-
-template <typename TargetConfiguration>
-Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
- : _function(function)
- , _nextBlock(0)
- , _executableAllocator(executableAllocator)
- , _jsGenerator(jsGenerator)
-{
- _addrs.resize(_function->basicBlockCount());
- _patches.resize(_function->basicBlockCount());
- _labelPatches.resize(_function->basicBlockCount());
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
-{
- _addrs[block->index()] = label();
- catchBlock = block->catchBlock;
- _nextBlock = nextBlock;
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
-{
- Q_UNUSED(current);
-
- if (target != _nextBlock)
- _patches[target->index()].push_back(jump());
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
-{
- _patches[targetBlock->index()].push_back(targetJump);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, Label target)
-{
- DataLabelPatch p;
- p.dataLabel = patch;
- p.target = target;
- _dataLabelPatches.push_back(p);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
-{
- _labelPatches[target->index()].push_back(patch);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
-{
- generateCJumpOnCompare(RelationalCondition::NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
- RegisterID left,
- TrustedImm32 right,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- if (trueBlock == _nextBlock) {
- Jump target = branch32(invert(cond), left, right);
- addPatch(falseBlock, target);
- } else {
- Jump target = branch32(cond, left, right);
- addPatch(trueBlock, target);
- jumpToBlock(currentBlock, falseBlock);
- }
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
- RegisterID left,
- RegisterID right,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- if (trueBlock == _nextBlock) {
- Jump target = branch32(invert(cond), left, right);
- addPatch(falseBlock, target);
- } else {
- Jump target = branch32(cond, left, right);
- addPatch(trueBlock, target);
- jumpToBlock(currentBlock, falseBlock);
- }
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer
-Assembler<TargetConfiguration>::loadAddressForWriting(RegisterID tmp, IR::Expr *e, WriteBarrier::Type *barrier)
-{
- if (barrier)
- *barrier = WriteBarrier::NoBarrier;
- IR::Temp *t = e->asTemp();
- if (t)
- return loadTempAddress(t);
- else
- return loadArgLocalAddressForWriting(tmp, e->asArgLocal(), barrier);
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadTempAddress(IR::Temp *t)
-{
- if (t->kind == IR::Temp::StackSlot)
- return stackSlotPointer(t);
- else
- Q_UNREACHABLE();
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer
-Assembler<TargetConfiguration>::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier)
-{
- if (barrier)
- *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier;
-
- int32_t offset = 0;
- int scope = al->scope;
- loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg);
-
- const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, outer));
- const qint32 localsOffset = targetStructureOffset(Heap::CallContextData::baseOffset + offsetof(Heap::CallContextData, function))
- + 8 // locals is always 8 bytes away from function, regardless of pointer size.
- + offsetof(ValueArray<0>, values);
-
- while (scope) {
- loadPtr(Address(baseReg, outerOffset), baseReg);
- --scope;
- }
- switch (al->kind) {
- case IR::ArgLocal::Formal:
- case IR::ArgLocal::ScopedFormal: {
- if (barrier && *barrier == WriteBarrier::Barrier) {
- // if we need a barrier, the baseReg has to point to the ExecutionContext
- // callData comes directly after locals, calculate the offset using that
- offset = localsOffset + _function->localsCountForScope(al) * sizeof(Value);
- offset += sizeof(CallData) + (al->index - 1) * sizeof(Value);
- } else {
- const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData));
- loadPtr(Address(baseReg, callDataOffset), baseReg);
- offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
- }
- } break;
- case IR::ArgLocal::Local:
- case IR::ArgLocal::ScopedLocal: {
- offset = localsOffset + al->index * sizeof(Value);
- } break;
- default:
- Q_UNREACHABLE();
- }
- return Pointer(baseReg, offset);
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
-{
- loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister);
- loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister);
- loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg);
- const int id = _jsGenerator->registerString(string);
- return Pointer(reg, id * RegisterSize);
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
-{
- return loadConstant(convertToValue<TargetPrimitive>(c), baseReg);
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg)
-{
- loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg);
- loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg);
- const int index = _jsGenerator->registerConstant(v.rawValue());
- return Address(baseReg, index * sizeof(QV4::Value));
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString &string)
-{
- const int id = _jsGenerator->registerString(string);
- move(TrustedImm32(id), reg);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination)
-{
- WriteBarrier::Type barrier;
- Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier);
- storeValue(value, addr, barrier);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
- const RegisterInformation &fpRegistersToSave)
-{
- platformEnterStandardStackFrame(this);
-
- move(StackPointerRegister, JITTargetPlatform::FramePointerRegister);
-
- const int frameSize = _stackLayout->calculateStackFrameSize();
- subPtr(TrustedImm32(frameSize), StackPointerRegister);
-
- Address slotAddr(JITTargetPlatform::FramePointerRegister, 0);
- for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) {
- Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
- slotAddr.offset -= sizeof(double);
- TargetConfiguration::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
- }
- for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) {
- Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister());
- slotAddr.offset -= RegisterSize;
- storePtr(regularRegistersToSave.at(i).reg<RegisterID>(), slotAddr);
- }
-
- platformFinishEnteringStandardStackFrame(this);
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
- const RegisterInformation &fpRegistersToSave)
-{
- Address slotAddr(JITTargetPlatform::FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
-
- // restore the callee saved registers
- for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) {
- Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister());
- loadPtr(slotAddr, regularRegistersToSave.at(i).reg<RegisterID>());
- slotAddr.offset += RegisterSize;
- }
- for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) {
- Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
- TargetConfiguration::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
- slotAddr.offset += sizeof(double);
- }
-
- Q_ASSERT(slotAddr.offset == 0);
-
- const int frameSize = _stackLayout->calculateStackFrameSize();
- platformLeaveStandardStackFrame(this, frameSize);
-}
-
-
-
-
-// Try to load the source expression into the destination FP register. This assumes that two
-// general purpose (integer) registers are available: the ScratchRegister and the
-// ReturnValueRegister. It returns a Jump if no conversion can be performed.
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::genTryDoubleConversion(IR::Expr *src, FPRegisterID dest)
-{
- switch (src->type) {
- case IR::DoubleType:
- moveDouble(toDoubleRegister(src, dest), dest);
- return Assembler::Jump();
- case IR::SInt32Type:
- convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister),
- dest);
- return Assembler::Jump();
- case IR::UInt32Type:
- convertUInt32ToDouble(toUInt32Register(src, Assembler::ScratchRegister),
- dest, Assembler::ReturnValueRegister);
- return Assembler::Jump();
- case IR::NullType:
- case IR::UndefinedType:
- case IR::BoolType:
- // TODO?
- case IR::StringType:
- return jump();
- default:
- break;
- }
-
- Q_ASSERT(src->asTemp() || src->asArgLocal());
-
- // It's not a number type, so it cannot be in a register.
- Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType);
-
- Assembler::Pointer tagAddr = loadAddressForReading(Assembler::ScratchRegister, src);
- tagAddr.offset += 4;
- load32(tagAddr, Assembler::ScratchRegister);
-
- // check if it's an int32:
- Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(quint32(ValueTypeInternal::Integer)));
- convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest);
- Assembler::Jump intDone = jump();
-
- // not an int, check if it's a double:
- isNoInt.link(this);
- Assembler::Jump isNoDbl = RegisterSizeDependentOps::checkIfTagRegisterIsDouble(this, ScratchRegister);
- toDoubleRegister(src, dest);
- intDone.link(this);
-
- return isNoDbl;
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchDouble(bool invertCondition, IR::AluOp op,
- IR::Expr *left, IR::Expr *right)
-{
- DoubleCondition cond;
- switch (op) {
- case IR::OpGt: cond = Assembler::DoubleGreaterThan; break;
- case IR::OpLt: cond = Assembler::DoubleLessThan; break;
- case IR::OpGe: cond = Assembler::DoubleGreaterThanOrEqual; break;
- case IR::OpLe: cond = Assembler::DoubleLessThanOrEqual; break;
- case IR::OpEqual:
- case IR::OpStrictEqual: cond = Assembler::DoubleEqual; break;
- case IR::OpNotEqual:
- case IR::OpStrictNotEqual: cond = Assembler::DoubleNotEqualOrUnordered; break; // No, the inversion of DoubleEqual is NOT DoubleNotEqual.
- default:
- Q_UNREACHABLE();
- }
- if (invertCondition)
- cond = TargetConfiguration::MacroAssembler::invert(cond);
-
- return TargetConfiguration::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, JITTargetPlatform::FPGpr1));
-}
-
-template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
-{
- Assembler::RelationalCondition cond;
- switch (op) {
- case IR::OpGt: cond = Assembler::GreaterThan; break;
- case IR::OpLt: cond = Assembler::LessThan; break;
- case IR::OpGe: cond = Assembler::GreaterThanOrEqual; break;
- case IR::OpLe: cond = Assembler::LessThanOrEqual; break;
- case IR::OpEqual:
- case IR::OpStrictEqual: cond = Assembler::Equal; break;
- case IR::OpNotEqual:
- case IR::OpStrictNotEqual: cond = Assembler::NotEqual; break;
- default:
- Q_UNREACHABLE();
- }
- if (invertCondition)
- cond = TargetConfiguration::MacroAssembler::invert(cond);
-
- return TargetConfiguration::MacroAssembler::branch32(cond,
- toInt32Register(left, Assembler::ScratchRegister),
- toInt32Register(right, Assembler::ReturnValueRegister));
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
-{
- _stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave));
-}
-
-template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave)
-{
- if (!s) {
- // this only happens if the method doesn't have a return statement and can
- // only exit through an exception
- } else if (IR::Temp *t = s->expr->asTemp()) {
- RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
- } else if (IR::Const *c = s->expr->asConst()) {
- auto retVal = convertToValue<TargetPrimitive>(c);
- RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
- } else {
- Q_UNREACHABLE();
- Q_UNUSED(s);
- }
-
- Label leaveStackFrame = label();
-
- const int locals = stackLayout().calculateJSStackFrameSize();
- subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
- storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
-
- leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
- ret();
-
- exceptionReturnLabel = label();
- auto retVal = TargetPrimitive::undefinedValue();
- RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
- jump(leaveStackFrame);
-}
-
-namespace {
-class QIODevicePrintStream: public FilePrintStream
-{
- Q_DISABLE_COPY(QIODevicePrintStream)
-
-public:
- explicit QIODevicePrintStream(QIODevice *dest)
- : FilePrintStream(0)
- , dest(dest)
- , buf(4096, '0')
- {
- Q_ASSERT(dest);
- }
-
- ~QIODevicePrintStream()
- {}
-
- void vprintf(const char* format, va_list argList) override 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() override
- {}
-
-private:
- QIODevice *dest;
- QByteArray buf;
-};
-} // anonymous namespace
-
-static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions)
-{
- for (QHash<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 = processedOutput.indexOf(ptrString);
- if (idx < 0)
- continue;
- idx = processedOutput.lastIndexOf('\n', idx);
- if (idx < 0)
- continue;
- processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value());
- }
-
- qDebug("%s", processedOutput.constData());
-}
-
-#if defined(Q_OS_LINUX)
-static FILE *pmap;
-
-static void qt_closePmap()
-{
- if (pmap) {
- fclose(pmap);
- pmap = 0;
- }
-}
-
-#endif
-
-template <typename TargetConfiguration>
-JSC::MacroAssemblerCodeRef Assembler<TargetConfiguration>::link(int *codeSize)
-{
- Label endOfCode = label();
-
- {
- for (size_t i = 0, ei = _patches.size(); i != ei; ++i) {
- Label target = _addrs.at(i);
- Q_ASSERT(target.isSet());
- for (Jump jump : qAsConst(_patches.at(i)))
- jump.linkTo(target, this);
- }
- }
-
- JSC::JSGlobalData dummy(_executableAllocator);
- JSC::LinkBuffer<typename TargetConfiguration::MacroAssembler> linkBuffer(dummy, this, 0);
-
- for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
- linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
-
- // link exception handlers
- for (Jump jump : qAsConst(exceptionPropagationJumps))
- linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
-
- {
- for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) {
- Label target = _addrs.at(i);
- Q_ASSERT(target.isSet());
- for (DataLabelPtr label : _labelPatches.at(i))
- linkBuffer.patch(label, linkBuffer.locationOf(target));
- }
- }
-
- *codeSize = linkBuffer.offsetOf(endOfCode);
-
- QByteArray name;
-
- JSC::MacroAssemblerCodeRef codeRef;
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
- if (showCode) {
- QHash<void*, const char*> functions;
-#ifndef QT_NO_DEBUG
- for (CallInfo call : qAsConst(_callInfos))
- functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName;
-#endif
-
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- WTF::setDataFile(new QIODevicePrintStream(&buf));
-
- name = _function->name->toUtf8();
- if (name.isEmpty())
- name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
- codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
-
- WTF::setDataFile(stderr);
- printDisassembledOutputWithCalls(buf.data(), functions);
- } else {
- codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
- }
-
-#if defined(Q_OS_LINUX)
- // 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");
- static bool profileInitialized = false;
- if (doProfile && !profileInitialized) {
- profileInitialized = true;
-
- char pname[PATH_MAX];
- snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map",
- (unsigned long)QCoreApplication::applicationPid());
-
- pmap = fopen(pname, "w");
- if (!pmap)
- qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname);
-
- // make sure we clean up nicely
- std::atexit(qt_closePmap);
- }
-
- if (pmap) {
- // this may have been pre-populated, if QV4_SHOW_ASM was on
- if (name.isEmpty()) {
- name = _function->name->toUtf8();
- if (name.isEmpty())
- name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
- }
-
- fprintf(pmap, "%llx %x %.*s\n",
- (long long unsigned int)codeRef.code().executableAddress(),
- *codeSize,
- name.length(),
- name.constData());
- fflush(pmap);
- }
-#endif
-
- return codeRef;
-}
-
-template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
-#if defined(V4_BOOTSTRAP)
-#if !CPU(ARM_THUMB2)
-template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
-#endif
-#if !CPU(ARM64)
-template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
-#endif
-#endif
-
-#endif
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
deleted file mode 100644
index 9e38696d7a..0000000000
--- a/src/qml/jit/qv4assembler_p.h
+++ /dev/null
@@ -1,1851 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4ASSEMBLER_P_H
-#define QV4ASSEMBLER_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/qv4global_p.h"
-#include "private/qv4jsir_p.h"
-#include "private/qv4isel_p.h"
-#include "private/qv4isel_util_p.h"
-#include "private/qv4value_p.h"
-#include "private/qv4context_p.h"
-#include "private/qv4engine_p.h"
-#include "private/qv4writebarrier_p.h"
-#include "qv4targetplatform_p.h"
-
-#include <config.h>
-#include <wtf/Vector.h>
-
-#include <climits>
-
-#if ENABLE(ASSEMBLER)
-
-#include <assembler/MacroAssembler.h>
-#include <assembler/MacroAssemblerCodeRef.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-struct CompilationUnit : public QV4::CompiledData::CompilationUnit
-{
- virtual ~CompilationUnit();
-
-#if !defined(V4_BOOTSTRAP)
- void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
-#endif
- void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
- bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
-
- // Coderef + execution engine
-
- QVector<JSC::MacroAssemblerCodeRef> codeRefs;
-};
-
-template <typename PlatformAssembler, TargetOperatingSystemSpecialization Specialization>
-struct AssemblerTargetConfiguration
-{
- typedef JSC::MacroAssembler<PlatformAssembler> MacroAssembler;
- typedef TargetPlatform<PlatformAssembler, Specialization> Platform;
- // More things coming here in the future, such as Target OS
-};
-
-#if CPU(ARM_THUMB2)
-typedef JSC::MacroAssemblerARMv7 DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#elif CPU(ARM64)
-typedef JSC::MacroAssemblerARM64 DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#elif CPU(ARM_TRADITIONAL)
-typedef JSC::MacroAssemblerARM DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#elif CPU(MIPS)
-typedef JSC::MacroAssemblerMIPS DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#elif CPU(X86)
-typedef JSC::MacroAssemblerX86 DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#elif CPU(X86_64)
-typedef JSC::MacroAssemblerX86_64 DefaultPlatformMacroAssembler;
-
-#if OS(WINDOWS)
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, WindowsSpecialization> DefaultAssemblerTargetConfiguration;
-#else
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#endif
-
-#elif CPU(SH4)
-typedef JSC::MacroAssemblerSH4 DefaultPlatformMacroAssembler;
-typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
-#endif
-
-#define isel_stringIfyx(s) #s
-#define isel_stringIfy(s) isel_stringIfyx(s)
-
-#define generateRuntimeCall(as, t, function, ...) \
- as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(QV4::Runtime::function), __VA_ARGS__)
-
-
-template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform, int RegisterSize>
-struct RegisterSizeDependentAssembler
-{
-};
-
-template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
-struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 4>
-{
- using RegisterID = typename JITAssembler::RegisterID;
- using FPRegisterID = typename JITAssembler::FPRegisterID;
- using RelationalCondition = typename JITAssembler::RelationalCondition;
- using ResultCondition = typename JITAssembler::ResultCondition;
- using Address = typename JITAssembler::Address;
- using Pointer = typename JITAssembler::Pointer;
- using TrustedImm32 = typename JITAssembler::TrustedImm32;
- using TrustedImm64 = typename JITAssembler::TrustedImm64;
- using Jump = typename JITAssembler::Jump;
- using Label = typename JITAssembler::Label;
- using ValueTypeInternal = Value::ValueTypeInternal_32;
- using TargetPrimitive = TargetPrimitive32;
-
- static void emitSetGrayBit(JITAssembler *as, RegisterID base)
- {
- bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
-
- as->push(TargetPlatform::EngineRegister); // free up one register for work
-
- RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
- as->move(base, grayBitmap);
- Q_ASSERT(base != grayBitmap);
- as->urshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
- as->lshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
- Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
-
- RegisterID index = base;
- as->move(base, index);
- as->sub32(grayBitmap, index);
- as->urshift32(TrustedImm32(Chunk::SlotSizeShift), index);
- RegisterID grayIndex = TargetPlatform::EngineRegister;
- as->move(index, grayIndex);
- as->urshift32(TrustedImm32(Chunk::BitShift), grayIndex);
- as->lshift32(TrustedImm32(2), grayIndex); // 4 bytes per quintptr
- as->add32(grayIndex, grayBitmap);
- as->and32(TrustedImm32(Chunk::Bits - 1), index);
-
- RegisterID bit = TargetPlatform::EngineRegister;
- as->move(TrustedImm32(1), bit);
- as->lshift32(index, bit);
-
- as->load32(Pointer(grayBitmap, 0), index);
- as->or32(bit, index);
- as->store32(index, Pointer(grayBitmap, 0));
-
- as->pop(TargetPlatform::EngineRegister);
- }
-
-#if WRITEBARRIER(none)
- static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
-#endif
-
- static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
- {
- as->MacroAssembler::loadDouble(addr, dest);
- }
-
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
- {
- as->MacroAssembler::storeDouble(source, addr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, addr);
- }
-
- static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
- {
- WriteBarrier::Type barrier;
- Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
- as->storeDouble(source, ptr, barrier);
- }
-
- static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
- {
- as->store32(TrustedImm32(value.value()), destination);
- destination.offset += 4;
- as->store32(TrustedImm32(value.tag()), destination);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, destination);
- }
-
- template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
- {
- as->loadDouble(source, TargetPlatform::FPGpr0);
- // We need to pass NoBarrier to storeDouble and call emitWriteBarrier ourselves, as the
- // code in storeDouble assumes the type we're storing is actually a double, something
- // that isn't always the case here.
- as->storeDouble(TargetPlatform::FPGpr0, destination, WriteBarrier::NoBarrier);
- if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, destination);
- }
-
- static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
- {
- as->MacroAssembler::loadDouble(as->loadConstant(c, TargetPlatform::ScratchRegister), target);
- }
-
- static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
- {
- as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
- }
-
- static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
- {
- Address destination = dest;
- as->store32(TargetPlatform::LowReturnValueRegister, destination);
- destination.offset += 4;
- as->store32(TargetPlatform::HighReturnValueRegister, destination);
- if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, dest);
- }
-
- static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
- {
- const auto lowReg = TargetPlatform::LowReturnValueRegister;
- const auto highReg = TargetPlatform::HighReturnValueRegister;
-
- if (t->kind == IR::Temp::PhysicalRegister) {
- switch (t->type) {
- case IR::DoubleType:
- as->moveDoubleToInts((FPRegisterID) t->index, lowReg, highReg);
- break;
- case IR::UInt32Type: {
- RegisterID srcReg = (RegisterID) t->index;
- Jump intRange = as->branch32(JITAssembler::GreaterThanOrEqual, srcReg, TrustedImm32(0));
- as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
- as->moveDoubleToInts(TargetPlatform::FPGpr0, lowReg, highReg);
- Jump done = as->jump();
- intRange.link(as);
- as->move(srcReg, lowReg);
- as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
- done.link(as);
- } break;
- case IR::SInt32Type:
- as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
- break;
- case IR::BoolType:
- as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Boolean)), highReg);
- break;
- default:
- Q_UNREACHABLE();
- }
- } else {
- Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, t);
- as->load32(addr, lowReg);
- addr.offset += 4;
- as->load32(addr, highReg);
- }
- }
-
- static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
- {
- as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister);
- as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(as);
- Q_UNUSED(temp);
- Q_UNUSED(dest);
- Q_UNUSED(argumentNumber);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(as);
- Q_UNUSED(al);
- Q_UNUSED(dest);
- Q_UNUSED(argumentNumber);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(as);
- Q_UNUSED(c);
- Q_UNUSED(dest);
- Q_UNUSED(argumentNumber);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(as);
- Q_UNUSED(expr);
- Q_UNUSED(dest);
- Q_UNUSED(argumentNumber);
- }
-
- static void zeroRegister(JITAssembler *as, RegisterID reg)
- {
- as->move(TrustedImm32(0), reg);
- }
-
- static void zeroStackSlot(JITAssembler *as, int slot)
- {
- as->poke(TrustedImm32(0), slot);
- }
-
- static void generateCJumpOnUndefined(JITAssembler *as,
- RelationalCondition cond, IR::Expr *right,
- RegisterID scratchRegister, RegisterID tagRegister,
- IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
- {
- Pointer tagAddr = as->loadAddressForReading(scratchRegister, right);
- as->load32(tagAddr, tagRegister);
- Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
- as->addPatch(falseBlock, j);
-
- tagAddr.offset += 4;
- as->load32(tagAddr, tagRegister);
- const TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
- Q_ASSERT(nextBlock == as->nextBlock());
- Q_UNUSED(nextBlock);
- as->generateCJumpOnCompare(cond, tagRegister, tag, currentBlock, trueBlock, falseBlock);
- }
-
- static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
- {
- Q_ASSERT(source->type == IR::VarType);
- // load the tag:
- Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
- Pointer tagAddr = addr;
- tagAddr.offset += 4;
- as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
-
- // check if it's an int32:
- Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
- TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)));
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- as->load32(addr, TargetPlatform::ReturnValueRegister);
- WriteBarrier::Type barrier;
- Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
- as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, targetAddr);
- } else {
- as->load32(addr, (RegisterID) targetTemp->index);
- }
- Jump intDone = as->jump();
-
- // not an int:
- fallback.link(as);
- generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
- as->storeInt32(TargetPlatform::ReturnValueRegister, target);
-
- intDone.link(as);
- }
-
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
- {
- as->store32(registerWithPtr, destAddr);
- destAddr.offset += 4;
- as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
- if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, destAddr);
- }
-
- static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
- {
- as->and32(TrustedImm32(Value::NotDouble_Mask), tagOrValueRegister);
- return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
- TrustedImm32(Value::NotDouble_Mask));
- }
-
- static void initializeLocalVariables(JITAssembler *as, int localsCount)
- {
- as->move(TrustedImm32(0), TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister);
- Label loop = as->label();
- as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
- as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister);
- as->store32(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
- as->add32(TrustedImm32(4), TargetPlatform::LocalsRegister);
- Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
- jump.linkTo(loop, as);
- }
-
- static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
- {
- as->and32(TrustedImm32(Value::NotDouble_Mask), tagRegister);
- Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(Value::NotDouble_Mask));
- return isNoDbl;
- }
-};
-
-template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
-struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 8>
-{
- using RegisterID = typename JITAssembler::RegisterID;
- using FPRegisterID = typename JITAssembler::FPRegisterID;
- using Address = typename JITAssembler::Address;
- using TrustedImm32 = typename JITAssembler::TrustedImm32;
- using TrustedImm64 = typename JITAssembler::TrustedImm64;
- using Pointer = typename JITAssembler::Pointer;
- using RelationalCondition = typename JITAssembler::RelationalCondition;
- using ResultCondition = typename JITAssembler::ResultCondition;
- using BranchTruncateType = typename JITAssembler::BranchTruncateType;
- using Jump = typename JITAssembler::Jump;
- using Label = typename JITAssembler::Label;
- using ValueTypeInternal = Value::ValueTypeInternal_64;
- using TargetPrimitive = TargetPrimitive64;
-
- static void emitSetGrayBit(JITAssembler *as, RegisterID base)
- {
- bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
-
- as->push(TargetPlatform::EngineRegister); // free up one register for work
-
- RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
- as->move(base, grayBitmap);
- Q_ASSERT(base != grayBitmap);
- as->urshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
- as->lshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
- Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
-
- RegisterID index = base;
- as->move(base, index);
- as->sub64(grayBitmap, index);
- as->urshift64(TrustedImm32(Chunk::SlotSizeShift), index);
- RegisterID grayIndex = TargetPlatform::EngineRegister;
- as->move(index, grayIndex);
- as->urshift64(TrustedImm32(Chunk::BitShift), grayIndex);
- as->lshift64(TrustedImm32(3), grayIndex); // 8 bytes per quintptr
- as->add64(grayIndex, grayBitmap);
- as->and64(TrustedImm32(Chunk::Bits - 1), index);
-
- RegisterID bit = TargetPlatform::EngineRegister;
- as->move(TrustedImm32(1), bit);
- as->lshift64(index, bit);
-
- as->load64(Pointer(grayBitmap, 0), index);
- as->or64(bit, index);
- as->store64(index, Pointer(grayBitmap, 0));
-
- as->pop(TargetPlatform::EngineRegister);
- }
-
-#if WRITEBARRIER(none)
- static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
-#endif
-
- static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
- {
- as->load64(addr, TargetPlatform::ReturnValueRegister);
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
- }
-
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
- {
- as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- as->store64(TargetPlatform::ReturnValueRegister, addr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, addr);
- }
-
- static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
- {
- as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- WriteBarrier::Type barrier;
- Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
- as->store64(TargetPlatform::ReturnValueRegister, ptr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, ptr);
- }
-
- static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
- {
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
- }
-
- static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
- {
- as->store64(TargetPlatform::ReturnValueRegister, dest);
- if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, dest);
- }
-
- static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
- {
- if (t->kind == IR::Temp::PhysicalRegister) {
- if (t->type == IR::DoubleType) {
- as->moveDoubleTo64((FPRegisterID) t->index,
- TargetPlatform::ReturnValueRegister);
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- } else if (t->type == IR::UInt32Type) {
- RegisterID srcReg = (RegisterID) t->index;
- Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0));
- as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
- as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- Jump done = as->jump();
- intRange.link(as);
- as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
- quint64 tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
- as->or64(TrustedImm64(tag << 32),
- TargetPlatform::ReturnValueRegister);
- done.link(as);
- } else {
- as->zeroExtend32ToPtr((RegisterID) t->index, TargetPlatform::ReturnValueRegister);
- quint64 tag;
- switch (t->type) {
- case IR::SInt32Type:
- tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
- break;
- case IR::BoolType:
- tag = quint64(QV4::Value::ValueTypeInternal_64::Boolean);
- break;
- default:
- tag = 31337; // bogus value
- Q_UNREACHABLE();
- }
- as->or64(TrustedImm64(tag << 32),
- TargetPlatform::ReturnValueRegister);
- }
- } else {
- as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier);
- }
- }
-
- static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
- {
- as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
- }
-
- static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
- {
- as->store64(TrustedImm64(value.rawValue()), destination);
- if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, destination);
- }
-
- template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
- {
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0);
- as->storeReturnValue(destination, barrier);
- }
-
- static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
- {
- Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
- int64_t i;
- memcpy(&i, &c->value, sizeof(double));
- as->move(TrustedImm64(i), TargetPlatform::ReturnValueRegister);
- as->move64ToDouble(TargetPlatform::ReturnValueRegister, target);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, Address addressOfValue, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
- as->load64(addressOfValue, dest);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- if (temp) {
- Pointer addr = as->loadTempAddress(temp);
- as->load64(addr, dest);
- } else {
- auto undefined = TargetPrimitive::undefinedValue();
- as->move(TrustedImm64(undefined.rawValue()), dest);
- }
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- if (al) {
- Pointer addr = as->loadArgLocalAddressForReading(dest, al);
- as->load64(addr, dest);
- } else {
- auto undefined = TargetPrimitive::undefinedValue();
- as->move(TrustedImm64(undefined.rawValue()), dest);
- }
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- auto v = convertToValue<TargetPrimitive64>(c);
- as->move(TrustedImm64(v.rawValue()), dest);
- }
-
- static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- if (!expr) {
- auto undefined = TargetPrimitive::undefinedValue();
- as->move(TrustedImm64(undefined.rawValue()), dest);
- } else if (IR::Temp *t = expr->asTemp()){
- loadArgumentInRegister(as, t, dest, argumentNumber);
- } else if (IR::ArgLocal *al = expr->asArgLocal()) {
- loadArgumentInRegister(as, al, dest, argumentNumber);
- } else if (IR::Const *c = expr->asConst()) {
- loadArgumentInRegister(as, c, dest, argumentNumber);
- } else {
- Q_ASSERT(!"unimplemented expression type in loadArgument");
- }
- }
-
- static void zeroRegister(JITAssembler *as, RegisterID reg)
- {
- as->move(TrustedImm64(0), reg);
- }
-
- static void zeroStackSlot(JITAssembler *as, int slot)
- {
- as->store64(TrustedImm64(0), as->addressForPoke(slot));
- }
-
- static void generateCJumpOnCompare(JITAssembler *as,
- RelationalCondition cond,
- RegisterID left,
- TrustedImm64 right,
- IR::BasicBlock *nextBlock,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
- {
- if (trueBlock == nextBlock) {
- Jump target = as->branch64(as->invert(cond), left, right);
- as->addPatch(falseBlock, target);
- } else {
- Jump target = as->branch64(cond, left, right);
- as->addPatch(trueBlock, target);
- as->jumpToBlock(currentBlock, falseBlock);
- }
- }
-
- static void generateCJumpOnUndefined(JITAssembler *as,
- RelationalCondition cond, IR::Expr *right,
- RegisterID scratchRegister, RegisterID tagRegister,
- IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
- {
- Pointer addr = as->loadAddressForReading(scratchRegister, right);
- as->load64(addr, tagRegister);
- const TrustedImm64 tag(0);
- generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
- }
-
- static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
- {
- Q_ASSERT(source->type == IR::VarType);
- Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
- as->load64(addr, TargetPlatform::ScratchRegister);
- as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
-
- // check if it's integer convertible
- as->urshift64(TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), TargetPlatform::ScratchRegister);
- Jump isIntConvertible = as->branch32(RelationalCondition::Equal, TargetPlatform::ScratchRegister, TrustedImm32(3));
-
- // nope, not integer convertible, so check for a double:
- as->urshift64(TrustedImm32(
- QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
- TargetPlatform::ScratchRegister);
- Jump fallback = as->branch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0));
-
- // it's a double
- as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0);
- Jump success =
- as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister,
- BranchTruncateType::BranchIfTruncateSuccessful);
-
- // not an int:
- fallback.link(as);
- generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
-
-
- isIntConvertible.link(as);
- success.link(as);
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- WriteBarrier::Type barrier;
- Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
- as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), targetAddr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, targetAddr);
- } else {
- as->storeInt32(TargetPlatform::ReturnValueRegister, target);
- }
- }
-
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
- {
- as->store64(registerWithPtr, destAddr);
- if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
- emitWriteBarrier(as, destAddr);
- }
-
- static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
- {
- as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagOrValueRegister);
- return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
- TrustedImm32(0));
- }
-
- static void initializeLocalVariables(JITAssembler *as, int localsCount)
- {
- as->move(TrustedImm64(0), TargetPlatform::ReturnValueRegister);
- as->move(TrustedImm32(localsCount), TargetPlatform::ScratchRegister);
- Label loop = as->label();
- as->store64(TargetPlatform::ReturnValueRegister, Address(TargetPlatform::LocalsRegister));
- as->add64(TrustedImm32(8), TargetPlatform::LocalsRegister);
- Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
- jump.linkTo(loop, as);
- }
-
- static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
- {
- as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagRegister);
- Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(0));
- return isNoDbl;
- }
-};
-
-template <typename TargetConfiguration>
-class Assembler : public TargetConfiguration::MacroAssembler, public TargetConfiguration::Platform
-{
- Q_DISABLE_COPY(Assembler)
-
-public:
- Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
-
- using MacroAssembler = typename TargetConfiguration::MacroAssembler;
- using RegisterID = typename MacroAssembler::RegisterID;
- using FPRegisterID = typename MacroAssembler::FPRegisterID;
- using Address = typename MacroAssembler::Address;
- using Label = typename MacroAssembler::Label;
- using Jump = typename MacroAssembler::Jump;
- using DataLabelPtr = typename MacroAssembler::DataLabelPtr;
- using TrustedImm32 = typename MacroAssembler::TrustedImm32;
- using TrustedImm64 = typename MacroAssembler::TrustedImm64;
- using TrustedImmPtr = typename MacroAssembler::TrustedImmPtr;
- using RelationalCondition = typename MacroAssembler::RelationalCondition;
- using typename MacroAssembler::DoubleCondition;
- using MacroAssembler::label;
- using MacroAssembler::move;
- using MacroAssembler::jump;
- using MacroAssembler::add32;
- using MacroAssembler::and32;
- using MacroAssembler::store32;
- using MacroAssembler::loadPtr;
- using MacroAssembler::load32;
- using MacroAssembler::branch32;
- using MacroAssembler::subDouble;
- using MacroAssembler::subPtr;
- using MacroAssembler::addPtr;
- using MacroAssembler::call;
- using MacroAssembler::poke;
- using MacroAssembler::branchTruncateDoubleToUint32;
- using MacroAssembler::or32;
- using MacroAssembler::moveDouble;
- using MacroAssembler::convertUInt32ToDouble;
- using MacroAssembler::invert;
- using MacroAssembler::convertInt32ToDouble;
- using MacroAssembler::rshift32;
- using MacroAssembler::storePtr;
- using MacroAssembler::ret;
-
- using JITTargetPlatform = typename TargetConfiguration::Platform;
- using JITTargetPlatform::RegisterArgumentCount;
- using JITTargetPlatform::StackSpaceAllocatedUponFunctionEntry;
- using JITTargetPlatform::RegisterSize;
- using JITTargetPlatform::StackAlignment;
- using JITTargetPlatform::ReturnValueRegister;
- using JITTargetPlatform::StackPointerRegister;
- using JITTargetPlatform::ScratchRegister;
- using JITTargetPlatform::EngineRegister;
- using JITTargetPlatform::StackShadowSpace;
- using JITTargetPlatform::registerForArgument;
- using JITTargetPlatform::FPGpr0;
- using JITTargetPlatform::platformEnterStandardStackFrame;
- using JITTargetPlatform::platformFinishEnteringStandardStackFrame;
- using JITTargetPlatform::platformLeaveStandardStackFrame;
-
- static qint32 targetStructureOffset(qint32 hostOffset)
- {
- Q_ASSERT(hostOffset % QT_POINTER_SIZE == 0);
- return (hostOffset * RegisterSize) / QT_POINTER_SIZE;
- }
-
- struct LookupCall {
- Address addr;
- uint getterSetterOffset;
-
- LookupCall(const Address &addr, uint getterSetterOffset)
- : addr(addr)
- , getterSetterOffset(getterSetterOffset)
- {}
- };
-
- struct RuntimeCall {
- Address addr;
-
- inline RuntimeCall(Runtime::RuntimeMethods method = Runtime::InvalidRuntimeMethod);
- bool isValid() const { return addr.offset >= 0; }
- };
-
- // Explicit type to allow distinguishing between
- // pushing an address itself or the value it points
- // to onto the stack when calling functions.
- struct Pointer : public Address
- {
- explicit Pointer(const Address& addr)
- : Address(addr)
- {}
- explicit Pointer(RegisterID reg, int32_t offset)
- : Address(reg, offset)
- {}
- };
-
- using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
- using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal;
- using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive;
-
- // V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage
- // collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned
- // by the garbage collector, so if any JS object needs to be retained, it should be put on the
- // JS stack.
- //
- // The "saved reg arg X" are on the C++ stack is used to store values in registers that need to
- // be passed by reference to native functions. It is fine to use the C++ stack, because only
- // non-object values can be stored in registers.
- //
- // Stack layout for the C++ stack:
- // return address
- // old FP <- FP
- // callee saved reg n
- // ...
- // callee saved reg 0
- // saved reg arg n
- // ...
- // saved reg arg 0 <- SP
- //
- // Stack layout for the JS stack:
- // function call argument n <- LocalsRegister
- // ...
- // function call argument 0
- // local 0
- // ...
- // local n
- class StackLayout
- {
- public:
- StackLayout(IR::Function *function, int maxArgCountForBuiltins, int normalRegistersToSave, int fpRegistersToSave)
- : normalRegistersToSave(normalRegistersToSave)
- , fpRegistersToSave(fpRegistersToSave)
- , maxOutgoingArgumentCount(function->maxNumberOfArguments)
- , localCount(function->tempCount)
- , savedRegCount(maxArgCountForBuiltins)
- {
-#if 0 // debug code
- qDebug("calleeSavedRegCount.....: %d",calleeSavedRegCount);
- qDebug("maxOutgoingArgumentCount: %d",maxOutgoingArgumentCount);
- qDebug("localCount..............: %d",localCount);
- qDebug("savedConstCount.........: %d",savedRegCount);
- for (int i = 0; i < maxOutgoingArgumentCount; ++i)
- qDebug("argumentAddressForCall(%d) = 0x%x / -0x%x", i,
- argumentAddressForCall(i).offset, -argumentAddressForCall(i).offset);
- for (int i = 0; i < localCount; ++i)
- qDebug("local(%d) = 0x%x / -0x%x", i, stackSlotPointer(i).offset,
- -stackSlotPointer(i).offset);
- qDebug("savedReg(0) = 0x%x / -0x%x", savedRegPointer(0).offset, -savedRegPointer(0).offset);
- qDebug("savedReg(1) = 0x%x / -0x%x", savedRegPointer(1).offset, -savedRegPointer(1).offset);
- qDebug("savedReg(2) = 0x%x / -0x%x", savedRegPointer(2).offset, -savedRegPointer(2).offset);
- qDebug("savedReg(3) = 0x%x / -0x%x", savedRegPointer(3).offset, -savedRegPointer(3).offset);
- qDebug("savedReg(4) = 0x%x / -0x%x", savedRegPointer(4).offset, -savedRegPointer(4).offset);
- qDebug("savedReg(5) = 0x%x / -0x%x", savedRegPointer(5).offset, -savedRegPointer(5).offset);
-
- qDebug("callDataAddress(0) = 0x%x", callDataAddress(0).offset);
-#endif
- }
-
- int calculateStackFrameSize() const
- {
- // sp was aligned before executing the call instruction. So, calculate all contents
- // that were saved after that aligned stack...:
- const int stackSpaceAllocatedOtherwise = StackSpaceAllocatedUponFunctionEntry
- + RegisterSize; // saved FramePointerRegister
-
- // ... then calculate the stuff we want to store ...:
- int frameSize = RegisterSize * normalRegistersToSave + sizeof(double) * fpRegistersToSave;
- frameSize += savedRegCount * sizeof(QV4::Value); // (these get written out as Values, not as native registers)
-
- Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX);
- // .. then align that chunk ..:
- frameSize = static_cast<int>(WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise));
- // ... which now holds our frame size + the extra stuff that was pushed due to the call.
- // So subtract that extra stuff, and we have our frame size:
- frameSize -= stackSpaceAllocatedOtherwise;
-
- return frameSize;
- }
-
- /// \return the stack frame size in number of Value items.
- int calculateJSStackFrameSize() const
- {
- return (localCount + sizeof(QV4::CallData)/sizeof(QV4::Value) - 1 + maxOutgoingArgumentCount) + 1;
- }
-
- Address stackSlotPointer(int idx) const
- {
- Q_ASSERT(idx >= 0);
- Q_ASSERT(idx < localCount);
-
- Pointer addr = callDataAddress(0);
- addr.offset -= sizeof(QV4::Value) * (idx + 1);
- return addr;
- }
-
- // Some run-time functions take (Value* args, int argc). This function is for populating
- // the args.
- Pointer argumentAddressForCall(int argument) const
- {
- Q_ASSERT(argument >= 0);
- Q_ASSERT(argument < maxOutgoingArgumentCount);
-
- const int index = maxOutgoingArgumentCount - argument;
- return Pointer(Assembler::LocalsRegister, sizeof(QV4::Value) * (-index));
- }
-
- Pointer callDataAddress(int offset = 0) const {
- return Pointer(Assembler::LocalsRegister, offset - (sizeof(QV4::CallData) + sizeof(QV4::Value) * (maxOutgoingArgumentCount - 1)));
- }
-
- Address savedRegPointer(int offset) const
- {
- Q_ASSERT(offset >= 0);
- Q_ASSERT(offset < savedRegCount);
-
- // Get the address of the bottom-most element of our frame:
- Address ptr(Assembler::FramePointerRegister, -calculateStackFrameSize());
- // This now is the element with offset 0. So:
- ptr.offset += offset * sizeof(QV4::Value);
- // and we're done!
- return ptr;
- }
-
- private:
- int normalRegistersToSave;
- int fpRegistersToSave;
-
- /// arg count for calls to JS functions
- int maxOutgoingArgumentCount;
-
- /// the number of spill slots needed by this function
- int localCount;
-
- /// used by built-ins to save arguments (e.g. constants) to the stack when they need to be
- /// passed by reference.
- int savedRegCount;
- };
-
- struct VoidType { VoidType() {} };
- static const VoidType Void;
-
- typedef JSC::FunctionPtr FunctionPtr;
-
-#ifndef QT_NO_DEBUG
- struct CallInfo {
- Label label;
- const char* functionName;
- };
-#endif
- struct PointerToValue {
- PointerToValue(IR::Expr *value)
- : value(value)
- {}
- IR::Expr *value;
- };
- struct StringToIndex {
- explicit StringToIndex(const QString &string) : string(string) {}
- QString string;
- };
- struct Reference {
- Reference(IR::Expr *value) : value(value) {
- Q_ASSERT(value->asTemp() || value->asArgLocal());
- }
- IR::Expr *value;
- };
-
- void callAbsolute(const char* /*functionName*/, const LookupCall &lookupCall)
- {
- call(lookupCall.addr);
- }
-
- void callAbsolute(const char *functionName, const RuntimeCall &runtimeCall)
- {
- call(runtimeCall.addr);
-#ifndef QT_NO_DEBUG
- // the code below is to get proper function names in the disassembly
- CallInfo info;
- info.functionName = functionName;
- info.label = label();
- _callInfos.append(info);
-#else
- Q_UNUSED(functionName)
-#endif
- }
-
- void registerBlock(IR::BasicBlock*, IR::BasicBlock *nextBlock);
- IR::BasicBlock *nextBlock() const { return _nextBlock; }
- void jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target);
- void addPatch(IR::BasicBlock* targetBlock, Jump targetJump);
- void addPatch(DataLabelPtr patch, Label target);
- void addPatch(DataLabelPtr patch, IR::BasicBlock *target);
- void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock);
- void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock);
- void generateCJumpOnUndefined(RelationalCondition cond, IR::Expr *right,
- RegisterID scratchRegister, RegisterID tagRegister,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
- {
- RegisterSizeDependentOps::generateCJumpOnUndefined(this, cond, right, scratchRegister, tagRegister,
- _nextBlock, currentBlock, trueBlock, falseBlock);
- }
-
- Jump generateIsDoubleCheck(RegisterID tagOrValueRegister)
- {
- return RegisterSizeDependentOps::generateIsDoubleCheck(this, tagOrValueRegister);
- }
-
- Jump genTryDoubleConversion(IR::Expr *src, FPRegisterID dest);
- Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
-
- Pointer loadAddressForWriting(RegisterID tmp, IR::Expr *t, WriteBarrier::Type *barrier);
- Pointer loadAddressForReading(RegisterID tmp, IR::Expr *t) {
- return loadAddressForWriting(tmp, t, 0);
- }
-
- Pointer loadTempAddress(IR::Temp *t);
- Pointer loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier);
- Pointer loadArgLocalAddressForReading(RegisterID baseReg, IR::ArgLocal *al) {
- return loadArgLocalAddressForWriting(baseReg, al, 0);
- }
- Pointer loadStringAddress(RegisterID reg, const QString &string);
- Address loadConstant(IR::Const *c, RegisterID baseReg);
- Address loadConstant(const TargetPrimitive &v, RegisterID baseReg);
- void loadStringRef(RegisterID reg, const QString &string);
- Pointer stackSlotPointer(IR::Temp *t) const
- {
- Q_ASSERT(t->kind == IR::Temp::StackSlot);
-
- return Pointer(_stackLayout->stackSlotPointer(t->index));
- }
-
- template <int argumentNumber>
- void saveOutRegister(PointerToValue arg)
- {
- if (!arg.value)
- return;
- if (IR::Temp *t = arg.value->asTemp()) {
- if (t->kind == IR::Temp::PhysicalRegister) {
- Pointer addr(_stackLayout->savedRegPointer(argumentNumber));
- switch (t->type) {
- case IR::BoolType:
- storeBool((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
- break;
- case IR::SInt32Type:
- storeInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
- break;
- case IR::UInt32Type:
- storeUInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
- break;
- case IR::DoubleType:
- storeDouble((FPRegisterID) t->index, addr, WriteBarrier::NoBarrier);
- break;
- default:
- Q_UNIMPLEMENTED();
- }
- }
- }
- }
-
- template <int, typename ArgType>
- void saveOutRegister(ArgType)
- {}
-
- void loadArgumentInRegister(RegisterID source, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- move(source, dest);
- }
-
- void loadArgumentInRegister(const Pointer& ptr, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
- addPtr(TrustedImm32(ptr.offset), ptr.base, dest);
- }
-
- void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
- {
- if (!temp.value) {
- RegisterSizeDependentOps::zeroRegister(this, dest);
- } else {
- Pointer addr = toAddress(dest, temp.value, argumentNumber, 0);
- loadArgumentInRegister(addr, dest, argumentNumber);
- }
- }
- void loadArgumentInRegister(StringToIndex temp, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
- loadStringRef(dest, temp.string);
- }
-
- void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
- {
- Q_ASSERT(temp.value);
- Pointer addr = loadAddressForReading(dest, temp.value);
- loadArgumentInRegister(addr, dest, argumentNumber);
- }
-
- void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
- {
- RegisterSizeDependentOps::loadArgumentInRegister(this, temp, dest, argumentNumber);
- }
-
- void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber)
- {
- RegisterSizeDependentOps::loadArgumentInRegister(this, al, dest, argumentNumber);
- }
-
- void loadArgumentInRegister(IR::Const* c, RegisterID dest, int argumentNumber)
- {
- RegisterSizeDependentOps::loadArgumentInRegister(this, c, dest, argumentNumber);
- }
-
- void loadArgumentInRegister(IR::Expr* expr, RegisterID dest, int argumentNumber)
- {
- RegisterSizeDependentOps::loadArgumentInRegister(this, expr, dest, argumentNumber);
- }
-
- void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- RegisterSizeDependentOps::zeroRegister(this, dest);
- if (imm32.m_value)
- move(imm32, dest);
- }
-
- void storeReturnValue(RegisterID dest, WriteBarrier::Type barrier = WriteBarrier::NoBarrier)
- {
- Q_UNUSED(barrier);
- Q_ASSERT(barrier == WriteBarrier::NoBarrier);
- move(ReturnValueRegister, dest);
- }
-
- void storeUInt32ReturnValue(RegisterID dest)
- {
- subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
- Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp, WriteBarrier::NoBarrier);
- toUInt32Register(tmp, dest);
- addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
- }
-
- void storeReturnValue(FPRegisterID dest)
- {
- RegisterSizeDependentOps::storeReturnValue(this, dest);
- }
-
- void storeReturnValue(const Pointer &dest, WriteBarrier::Type barrier)
- {
- RegisterSizeDependentOps::storeReturnValue(this, dest, barrier);
- }
-
- void storeReturnValue(IR::Expr *target)
- {
- if (!target)
- return;
-
- IR::Temp *temp = target->asTemp();
- if (temp && temp->kind == IR::Temp::PhysicalRegister) {
- if (temp->type == IR::DoubleType)
- storeReturnValue((FPRegisterID) temp->index);
- else if (temp->type == IR::UInt32Type)
- storeUInt32ReturnValue((RegisterID) temp->index);
- else
- storeReturnValue((RegisterID) temp->index);
- return;
- } else {
- WriteBarrier::Type barrier;
- Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
- storeReturnValue(addr, barrier);
- }
- }
-
- void storeReturnValue(VoidType)
- {
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(RegisterID reg, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- poke(reg, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(TrustedImm32 value, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- poke(value, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(const Pointer& ptr, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
-
- addPtr(TrustedImm32(ptr.offset), ptr.base, ScratchRegister);
- poke(ScratchRegister, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(PointerToValue temp, int argumentNumber)
- {
- if (temp.value) {
- Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber, 0);
- loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
- } else {
- RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
- }
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(StringToIndex temp, int argumentNumber)
- {
- Q_UNUSED(argumentNumber);
- loadStringRef(ScratchRegister, temp.string);
- poke(ScratchRegister, StackSlot);
- }
-
- template <int StackSlot>
- void loadArgumentOnStack(Reference temp, int argumentNumber)
- {
- Q_ASSERT (temp.value);
-
- Pointer ptr = loadAddressForReading(ScratchRegister, temp.value);
- loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
- }
-
- void loadDouble(IR::Expr *source, FPRegisterID dest)
- {
- IR::Temp *sourceTemp = source->asTemp();
- if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
- moveDouble((FPRegisterID) sourceTemp->index, dest);
- return;
- }
- Pointer ptr = loadAddressForReading(ScratchRegister, source);
- loadDouble(ptr, dest);
- }
-
- void storeDouble(FPRegisterID source, IR::Expr* target)
- {
- IR::Temp *targetTemp = target->asTemp();
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- moveDouble(source, (FPRegisterID) targetTemp->index);
- return;
- }
- RegisterSizeDependentOps::storeDouble(this, source, target);
- }
-
- void loadDouble(Address addr, FPRegisterID dest)
- {
- RegisterSizeDependentOps::loadDouble(this, addr, dest);
- }
-
- void storeDouble(FPRegisterID source, Address addr, WriteBarrier::Type barrier)
- {
- RegisterSizeDependentOps::storeDouble(this, source, addr, barrier);
- }
-
- template <typename Result, typename Source>
- void copyValue(Result result, Source source, WriteBarrier::Type barrier);
- template <typename Result>
- void copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier);
-
- // The scratch register is used to calculate the temp address for the source.
- void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister, WriteBarrier::Type barrier)
- {
- Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
- Q_ASSERT(target.base != scratchRegister);
- loadRawValue(loadAddressForReading(scratchRegister, source), FPGpr0);
- storeRawValue(FPGpr0, target, barrier);
- }
-
- // The scratch register is used to calculate the temp address for the source.
- void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
- {
- loadRawValue(source, fpScratchRegister);
- WriteBarrier::Type barrier;
- Pointer dest = loadAddressForWriting(scratchRegister, target, &barrier);
- storeRawValue(fpScratchRegister, dest, barrier);
- }
-
- void loadRawValue(Pointer source, FPRegisterID dest)
- {
- TargetConfiguration::MacroAssembler::loadDouble(source, dest);
- }
-
- void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier)
- {
- TargetConfiguration::MacroAssembler::storeDouble(source, dest);
- if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
- RegisterSizeDependentOps::emitWriteBarrier(this, dest);
- }
-
- void storeValue(TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
- {
- RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
- }
-
- void storeValue(TargetPrimitive value, IR::Expr* temp);
-
- void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) {
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- RegisterSizeDependentOps::emitWriteBarrier(this, addr);
- }
-
- void enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
- const RegisterInformation &fpRegistersToSave);
- void leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
- const RegisterInformation &fpRegistersToSave);
-
- void checkException() {
- this->load8(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister);
- Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
- if (catchBlock)
- addPatch(catchBlock, exceptionThrown);
- else
- exceptionPropagationJumps.append(exceptionThrown);
- }
- void jumpToExceptionHandler() {
- Jump exceptionThrown = jump();
- if (catchBlock)
- addPatch(catchBlock, exceptionThrown);
- else
- exceptionPropagationJumps.append(exceptionThrown);
- }
-
- template <int argumentNumber, typename T>
- void loadArgumentOnStackOrRegister(const T &value)
- {
- if (argumentNumber < RegisterArgumentCount)
- loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber);
- else
- loadArgumentOnStack<argumentNumber - RegisterArgumentCount + (StackShadowSpace / RegisterSize)>(value, argumentNumber);
- }
-
- template <int argumentNumber>
- void loadArgumentOnStackOrRegister(const VoidType &value)
- {
- Q_UNUSED(value);
- }
-
- template <bool selectFirst, int First, int Second>
- struct Select
- {
- enum { Chosen = First };
- };
-
- template <int First, int Second>
- struct Select<false, First, Second>
- {
- enum { Chosen = Second };
- };
-
- template <int ArgumentIndex, typename Parameter>
- struct SizeOnStack
- {
- enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, RegisterSize, 0>::Chosen };
- };
-
- template <int ArgumentIndex>
- struct SizeOnStack<ArgumentIndex, VoidType>
- {
- enum { Size = 0 };
- };
-
- template <typename T> bool prepareCall(T &)
- { return true; }
-
- bool prepareCall(LookupCall &lookupCall)
- {
- // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
-
- // load the table from the context
- loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister);
- loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lookups))),
- lookupCall.addr.base);
- // pre-calculate the indirect address for the lookupCall table:
- if (lookupCall.addr.offset)
- addPtr(TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
- // store it as the first argument
- loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
- // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
- lookupCall.addr.offset = lookupCall.getterSetterOffset;
- return false;
- }
-
- template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
- {
- int stackSpaceNeeded = SizeOnStack<0, Arg1>::Size
- + SizeOnStack<1, Arg2>::Size
- + SizeOnStack<2, Arg3>::Size
- + SizeOnStack<3, Arg4>::Size
- + SizeOnStack<4, Arg5>::Size
- + SizeOnStack<5, Arg6>::Size
- + StackShadowSpace;
-
- if (stackSpaceNeeded) {
- Q_ASSERT(stackSpaceNeeded < (INT_MAX - StackAlignment));
- stackSpaceNeeded = static_cast<int>(WTF::roundUpToMultipleOf(StackAlignment, stackSpaceNeeded));
- subPtr(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
- }
-
- // First save any arguments that reside in registers, because they could be overwritten
- // if that register is also used to pass arguments.
- saveOutRegister<5>(arg6);
- saveOutRegister<4>(arg5);
- saveOutRegister<3>(arg4);
- saveOutRegister<2>(arg3);
- saveOutRegister<1>(arg2);
- saveOutRegister<0>(arg1);
-
- loadArgumentOnStackOrRegister<5>(arg6);
- loadArgumentOnStackOrRegister<4>(arg5);
- loadArgumentOnStackOrRegister<3>(arg4);
- loadArgumentOnStackOrRegister<2>(arg3);
- loadArgumentOnStackOrRegister<1>(arg2);
-
- if (prepareCall(function))
- loadArgumentOnStackOrRegister<0>(arg1);
-
- if (JITTargetPlatform::gotRegister != -1)
- load32(Address(JITTargetPlatform::FramePointerRegister, JITTargetPlatform::savedGOTRegisterSlotOnStack()), static_cast<RegisterID>(JITTargetPlatform::gotRegister)); // restore the GOT ptr
-
- callAbsolute(functionName, function);
-
- if (stackSpaceNeeded)
- addPtr(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
-
- if (needsExceptionCheck) {
- checkException();
- }
-
- storeReturnValue(r);
-
- }
-
- template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
- {
- generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, arg4, arg5, VoidType());
- }
-
- template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
- {
- generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, arg4, VoidType(), VoidType());
- }
-
- template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3)
- {
- generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, arg3, VoidType(), VoidType(), VoidType());
- }
-
- template <typename ArgRet, typename Callable, typename Arg1, typename Arg2>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2)
- {
- generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, arg2, VoidType(), VoidType(), VoidType(), VoidType());
- }
-
- template <typename ArgRet, typename Callable, typename Arg1>
- void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1)
- {
- generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType());
- }
-
- Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset, WriteBarrier::Type *barrier)
- {
- if (barrier)
- *barrier = WriteBarrier::NoBarrier;
- if (IR::Const *c = e->asConst()) {
- Address addr = _stackLayout->savedRegPointer(offset);
- Address tagAddr = addr;
- tagAddr.offset += 4;
-
- auto v = convertToValue<TargetPrimitive>(c);
- store32(TrustedImm32(v.value()), addr);
- store32(TrustedImm32(v.tag()), tagAddr);
- return Pointer(addr);
- }
-
- if (IR::Temp *t = e->asTemp())
- if (t->kind == IR::Temp::PhysicalRegister)
- return Pointer(_stackLayout->savedRegPointer(offset));
-
- return loadAddressForWriting(tmpReg, e, barrier);
- }
-
- void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
- {
- store32(reg, addr);
- addr.offset += 4;
- store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- RegisterSizeDependentOps::emitWriteBarrier(this, addr);
- }
-
- void storeBool(RegisterID src, RegisterID dest)
- {
- move(src, dest);
- }
-
- void storeBool(RegisterID reg, IR::Expr *target)
- {
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) targetTemp->index);
- return;
- }
- }
-
- WriteBarrier::Type barrier;
- Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
- storeBool(reg, addr, barrier);
- }
-
- void storeBool(bool value, IR::Expr *target) {
- TrustedImm32 trustedValue(value ? 1 : 0);
-
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(trustedValue, (RegisterID) targetTemp->index);
- return;
- }
- }
-
- move(trustedValue, ScratchRegister);
- storeBool(ScratchRegister, target);
- }
-
- void storeInt32(RegisterID src, RegisterID dest)
- {
- move(src, dest);
- }
-
- void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
- {
- store32(reg, addr);
- addr.offset += 4;
- store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr);
- if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
- RegisterSizeDependentOps::emitWriteBarrier(this, addr);
- }
-
- void storeInt32(RegisterID reg, IR::Expr *target)
- {
- IR::Temp *targetTemp = target->asTemp();
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) targetTemp->index);
- } else {
- WriteBarrier::Type barrier;
- Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
- storeInt32(reg, addr, barrier);
- }
- }
-
- void storeUInt32(RegisterID src, RegisterID dest)
- {
- move(src, dest);
- }
-
- void storeUInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
- {
- // The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
- Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
- convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
- storeDouble(FPGpr0, addr, barrier);
- Jump done = jump();
- intRange.link(this);
- storeInt32(reg, addr, barrier);
- done.link(this);
- }
-
- void storeUInt32(RegisterID reg, IR::Expr *target)
- {
- IR::Temp *targetTemp = target->asTemp();
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) targetTemp->index);
- } else {
- WriteBarrier::Type barrier;
- Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
- storeUInt32(reg, addr, barrier);
- }
- }
-
- FPRegisterID toDoubleRegister(IR::Expr *e, FPRegisterID target = FPGpr0)
- {
- if (IR::Const *c = e->asConst()) {
- RegisterSizeDependentOps::loadDoubleConstant(this, c, target);
- return target;
- }
-
- if (IR::Temp *t = e->asTemp())
- if (t->kind == IR::Temp::PhysicalRegister)
- return (FPRegisterID) t->index;
-
- loadDouble(e, target);
- return target;
- }
-
- RegisterID toBoolRegister(IR::Expr *e, RegisterID scratchReg)
- {
- return toInt32Register(e, scratchReg);
- }
-
- RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg)
- {
- if (IR::Const *c = e->asConst()) {
- move(TrustedImm32(convertToValue<Primitive>(c).int_32()), scratchReg);
- return scratchReg;
- }
-
- if (IR::Temp *t = e->asTemp())
- if (t->kind == IR::Temp::PhysicalRegister)
- return (RegisterID) t->index;
-
- return toInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
- }
-
- RegisterID toInt32Register(Pointer addr, RegisterID scratchReg)
- {
- load32(addr, scratchReg);
- return scratchReg;
- }
-
- RegisterID toUInt32Register(IR::Expr *e, RegisterID scratchReg)
- {
- if (IR::Const *c = e->asConst()) {
- move(TrustedImm32(unsigned(c->value)), scratchReg);
- return scratchReg;
- }
-
- if (IR::Temp *t = e->asTemp())
- if (t->kind == IR::Temp::PhysicalRegister)
- return (RegisterID) t->index;
-
- return toUInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
- }
-
- RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
- {
- Q_ASSERT(addr.base != scratchReg);
-
- // The UInt32 representation in QV4::Value is really convoluted. See also storeUInt32.
- Pointer tagAddr = addr;
- tagAddr.offset += 4;
- load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(quint32(ValueTypeInternal::Integer)));
-
- // it's not in signed int range, so load it as a double, and truncate it down
- loadDouble(addr, FPGpr0);
- Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg);
- subDouble(inversionAddress, FPGpr0);
- Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
- canNeverHappen.link(this);
- or32(TrustedImm32(1 << 31), scratchReg);
- Jump done = jump();
-
- inIntRange.link(this);
- load32(addr, scratchReg);
-
- done.link(this);
- return scratchReg;
- }
-
- void returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave);
-
- JSC::MacroAssemblerCodeRef link(int *codeSize);
-
- void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
- const StackLayout &stackLayout() const { return *_stackLayout.data(); }
- void initializeLocalVariables()
- {
- const int locals = _stackLayout->calculateJSStackFrameSize();
- if (locals <= 0)
- return;
- loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))), JITTargetPlatform::LocalsRegister);
- RegisterSizeDependentOps::initializeLocalVariables(this, locals);
- storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
- }
-
- Label exceptionReturnLabel;
- IR::BasicBlock * catchBlock;
- QVector<Jump> exceptionPropagationJumps;
-private:
- QScopedPointer<const StackLayout> _stackLayout;
- IR::Function *_function;
- std::vector<Label> _addrs;
- std::vector<std::vector<Jump>> _patches;
-#ifndef QT_NO_DEBUG
- QVector<CallInfo> _callInfos;
-#endif
-
- struct DataLabelPatch {
- DataLabelPtr dataLabel;
- Label target;
- };
- std::vector<DataLabelPatch> _dataLabelPatches;
-
- std::vector<std::vector<DataLabelPtr>> _labelPatches;
- IR::BasicBlock *_nextBlock;
-
- QV4::ExecutableAllocator *_executableAllocator;
- QV4::Compiler::JSUnitGenerator *_jsGenerator;
-};
-
-template <typename TargetConfiguration>
-const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
-
-template <typename TargetConfiguration>
-template <typename Result, typename Source>
-void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier)
-{
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
-}
-
-template <typename TargetConfiguration>
-template <typename Result>
-void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier)
-{
- if (source->type == IR::BoolType) {
- RegisterID reg = toInt32Register(source, ScratchRegister);
- storeBool(reg, result, barrier);
- } else if (source->type == IR::SInt32Type) {
- RegisterID reg = toInt32Register(source, ScratchRegister);
- storeInt32(reg, result, barrier);
- } else if (source->type == IR::UInt32Type) {
- RegisterID reg = toUInt32Register(source, ScratchRegister);
- storeUInt32(reg, result, barrier);
- } else if (source->type == IR::DoubleType) {
- storeDouble(toDoubleRegister(source), result, barrier);
- } else if (source->asTemp() || source->asArgLocal()) {
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
- } else if (IR::Const *c = source->asConst()) {
- auto v = convertToValue<TargetPrimitive>(c);
- storeValue(v, result, barrier);
- } else {
- Q_UNREACHABLE();
- }
-}
-
-template <typename TargetConfiguration>
-inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(Runtime::RuntimeMethods method)
- : addr(Assembler::EngineRegister,
- method == Runtime::InvalidRuntimeMethod ? -1 : (Assembler<TargetConfiguration>::targetStructureOffset(offsetof(EngineBase, runtime) + Runtime::runtimeMethodOffset(method))))
-{
-}
-
-} // end of namespace JIT
-} // end of namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // ENABLE(ASSEMBLER)
-
-#endif // QV4ISEL_MASM_P_H
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
deleted file mode 100644
index a1c65f644c..0000000000
--- a/src/qml/jit/qv4binop.cpp
+++ /dev/null
@@ -1,665 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qv4binop_p.h>
-#include <qv4assembler_p.h>
-
-#if ENABLE(ASSEMBLER)
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-template <typename JITAssembler>
-struct ArchitectureSpecificBinaryOperation
-{
- using FPRegisterID = typename JITAssembler::FPRegisterID;
-
- static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- Q_UNUSED(as);
- Q_UNUSED(lhs);
- Q_UNUSED(rhs);
- Q_UNUSED(targetReg);
- return false;
- }
- static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- Q_UNUSED(as);
- Q_UNUSED(lhs);
- Q_UNUSED(rhs);
- Q_UNUSED(targetReg);
- return false;
- }
- static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- Q_UNUSED(as);
- Q_UNUSED(lhs);
- Q_UNUSED(rhs);
- Q_UNUSED(targetReg);
- return false;
- }
- static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- Q_UNUSED(as);
- Q_UNUSED(lhs);
- Q_UNUSED(rhs);
- Q_UNUSED(targetReg);
- return false;
- }
-};
-
-#if CPU(X86)
-template <>
-struct ArchitectureSpecificBinaryOperation<Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>>>
-{
- using JITAssembler = Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>>;
- using FPRegisterID = JITAssembler::FPRegisterID;
- using Address = JITAssembler::Address;
-
- static bool doubleAdd(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
- as->addDouble(addr, targetReg);
- return true;
- }
- if (IR::Temp *t = rhs->asTemp()) { // Y = X + [temp-memory-address] -> Y = X; Y += [temp-memory-address]
- if (t->kind != IR::Temp::PhysicalRegister) {
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- as->addDouble(as->loadTempAddress(t), targetReg);
- return true;
- }
- }
- return false;
- }
- static bool doubleMul(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
- as->mulDouble(addr, targetReg);
- return true;
- }
- if (IR::Temp *t = rhs->asTemp()) { // Y = X * [temp-memory-address] -> Y = X; Y *= [temp-memory-address]
- if (t->kind != IR::Temp::PhysicalRegister) {
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- as->mulDouble(as->loadTempAddress(t), targetReg);
- return true;
- }
- }
- return false;
- }
- static bool doubleSub(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
- as->subDouble(addr, targetReg);
- return true;
- }
- if (IR::Temp *t = rhs->asTemp()) { // Y = X - [temp-memory-address] -> Y = X; Y -= [temp-memory-address]
- if (t->kind != IR::Temp::PhysicalRegister) {
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- as->subDouble(as->loadTempAddress(t), targetReg);
- return true;
- }
- }
- return false;
- }
- static bool doubleDiv(JITAssembler *as, IR::Expr *lhs, IR::Expr *rhs, FPRegisterID targetReg)
- {
- if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
- as->divDouble(addr, targetReg);
- return true;
- }
- if (IR::Temp *t = rhs->asTemp()) { // Y = X / [temp-memory-address] -> Y = X; Y /= [temp-memory-address]
- if (t->kind != IR::Temp::PhysicalRegister) {
- as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- as->divDouble(as->loadTempAddress(t), targetReg);
- return true;
- }
- }
- return false;
- }
-};
-#endif
-
-#define OP(op) \
- { "Runtime::" isel_stringIfy(op), QV4::Runtime::op, QV4::Runtime::InvalidRuntimeMethod, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
-#define OPCONTEXT(op) \
- { "Runtime::" isel_stringIfy(op), QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::op, 0, 0, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
-
-#define INLINE_OP(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), QV4::Runtime::op, QV4::Runtime::InvalidRuntimeMethod, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
-#define INLINE_OPCONTEXT(op, memOp, immOp) \
- { "Runtime::" isel_stringIfy(op), QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::op, memOp, immOp, QV4::Runtime::Method_##op##_NeedsExceptionCheck }
-
-#define NULL_OP \
- { 0, QV4::Runtime::InvalidRuntimeMethod, QV4::Runtime::InvalidRuntimeMethod, 0, 0, false }
-
-template <typename JITAssembler>
-const typename Binop<JITAssembler>::OpInfo Binop<JITAssembler>::operations[IR::LastAluOp + 1] = {
- NULL_OP, // OpInvalid
- NULL_OP, // OpIfTrue
- NULL_OP, // OpNot
- NULL_OP, // OpUMinus
- NULL_OP, // OpUPlus
- NULL_OP, // OpCompl
- NULL_OP, // OpIncrement
- NULL_OP, // OpDecrement
-
- INLINE_OP(bitAnd, &Binop<JITAssembler>::inline_and32, &Binop<JITAssembler>::inline_and32), // OpBitAnd
- INLINE_OP(bitOr, &Binop<JITAssembler>::inline_or32, &Binop<JITAssembler>::inline_or32), // OpBitOr
- INLINE_OP(bitXor, &Binop<JITAssembler>::inline_xor32, &Binop<JITAssembler>::inline_xor32), // OpBitXor
-
- INLINE_OPCONTEXT(add, &Binop<JITAssembler>::inline_add32, &Binop<JITAssembler>::inline_add32), // OpAdd
- INLINE_OP(sub, &Binop<JITAssembler>::inline_sub32, &Binop<JITAssembler>::inline_sub32), // OpSub
- INLINE_OP(mul, &Binop<JITAssembler>::inline_mul32, &Binop<JITAssembler>::inline_mul32), // OpMul
-
- OP(div), // OpDiv
- OP(mod), // OpMod
-
- INLINE_OP(shl, &Binop<JITAssembler>::inline_shl32, &Binop<JITAssembler>::inline_shl32), // OpLShift
- INLINE_OP(shr, &Binop<JITAssembler>::inline_shr32, &Binop<JITAssembler>::inline_shr32), // OpRShift
- INLINE_OP(ushr, &Binop<JITAssembler>::inline_ushr32, &Binop<JITAssembler>::inline_ushr32), // OpURShift
-
- OP(greaterThan), // OpGt
- OP(lessThan), // OpLt
- OP(greaterEqual), // OpGe
- OP(lessEqual), // OpLe
- OP(equal), // OpEqual
- OP(notEqual), // OpNotEqual
- OP(strictEqual), // OpStrictEqual
- OP(strictNotEqual), // OpStrictNotEqual
-
- OPCONTEXT(instanceof), // OpInstanceof
- OPCONTEXT(in), // OpIn
-
- NULL_OP, // OpAnd
- NULL_OP // OpOr
-};
-
-
-
-template <typename JITAssembler>
-void Binop<JITAssembler>::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
-{
- if (op != IR::OpMod
- && lhs->type == IR::DoubleType && rhs->type == IR::DoubleType) {
- doubleBinop(lhs, rhs, target);
- return;
- }
- if (lhs->type == IR::SInt32Type && rhs->type == IR::SInt32Type) {
- if (int32Binop(lhs, rhs, target))
- return;
- }
-
- Jump done;
- if (lhs->type != IR::StringType && rhs->type != IR::StringType)
- done = genInlineBinop(lhs, rhs, target);
-
- // TODO: inline var===null and var!==null
- Binop::OpInfo info = Binop::operation(op);
-
- if (op == IR::OpAdd &&
- (lhs->type == IR::StringType || rhs->type == IR::StringType)) {
- const Binop::OpInfo stringAdd = OPCONTEXT(addString);
- info = stringAdd;
- }
-
- typename JITAssembler::RuntimeCall fallBack(info.fallbackImplementation);
- typename JITAssembler::RuntimeCall context(info.contextImplementation);
- if (fallBack.isValid()) {
- as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack,
- PointerToValue(lhs),
- PointerToValue(rhs));
- } else if (context.isValid()) {
- as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context,
- JITAssembler::EngineRegister,
- PointerToValue(lhs),
- PointerToValue(rhs));
- } else {
- Q_ASSERT(!"unreachable");
- }
-
- if (done.isSet())
- done.link(as);
-
-}
-
-template <typename JITAssembler>
-void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
-{
- IR::Temp *targetTemp = target->asTemp();
- FPRegisterID targetReg;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- targetReg = (FPRegisterID) targetTemp->index;
- else
- targetReg = JITAssembler::FPGpr0;
-
- switch (op) {
- case IR::OpAdd:
- if (lhs->asConst())
- std::swap(lhs, rhs); // Y = constant + X -> Y = X + constant
-
- if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleAdd(as, lhs, rhs, targetReg))
- break;
-
- as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
- break;
-
- case IR::OpMul:
- if (lhs->asConst())
- std::swap(lhs, rhs); // Y = constant * X -> Y = X * constant
-
- if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleMul(as, lhs, rhs, targetReg))
- break;
-
- as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
- break;
-
- case IR::OpSub:
- if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleSub(as, lhs, rhs, targetReg))
- break;
-
- if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
- && targetTemp
- && targetTemp->kind == IR::Temp::PhysicalRegister
- && targetTemp->index == rhs->asTemp()->index) { // Y = X - Y -> Tmp = Y; Y = X - Tmp
- as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
- as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
- break;
- }
-
- as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
- break;
-
- case IR::OpDiv:
- if (ArchitectureSpecificBinaryOperation<JITAssembler>::doubleDiv(as, lhs, rhs, targetReg))
- break;
-
- if (rhs->asTemp() && rhs->asTemp()->kind == IR::Temp::PhysicalRegister
- && targetTemp
- && targetTemp->kind == IR::Temp::PhysicalRegister
- && targetTemp->index == rhs->asTemp()->index) { // Y = X / Y -> Tmp = Y; Y = X / Tmp
- as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
- as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
- break;
- }
-
- as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
- break;
-
- default: {
- Jump trueCase = as->branchDouble(false, op, lhs, rhs);
- as->storeBool(false, target);
- Jump done = as->jump();
- trueCase.link(as);
- as->storeBool(true, target);
- done.link(as);
- } return;
- }
-
- if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- as->storeDouble(targetReg, target);
-}
-
-template <typename JITAssembler>
-bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
-{
- Q_ASSERT(leftSource->type == IR::SInt32Type);
- Q_ASSERT(rightSource->type == IR::SInt32Type);
-
- switch (op) {
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpAdd:
- case IR::OpMul:
- if (leftSource->asConst()) // X = Const op Y -> X = Y op Const
- std::swap(leftSource, rightSource);
- else if (IR::Temp *t = leftSource->asTemp()) {
- if (t->kind != IR::Temp::PhysicalRegister) // X = [address] op Y -> X = Y op [address]
- std::swap(leftSource, rightSource);
- }
- break;
-
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- case IR::OpSub:
- // handled by this method, but we can't flip operands.
- break;
-
- default:
- return false; // not handled by this method, stop here.
- }
-
- bool inplaceOpWithAddress = false;
-
- IR::Temp *targetTemp = target->asTemp();
- RegisterID targetReg = JITAssembler::ReturnValueRegister;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- IR::Temp *rhs = rightSource->asTemp();
- if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) {
- // We try to load leftSource into the target's register, but we can't do that if
- // the target register is the same as rightSource.
- targetReg = (RegisterID) targetTemp->index;
- } else if (rhs && rhs->kind == IR::Temp::PhysicalRegister && targetTemp->index == rhs->index) {
- // However, if the target register is the same as the rightSource register, we can flip
- // the operands for certain operations.
- switch (op) {
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpAdd:
- case IR::OpMul:
- // X = Y op X -> X = X op Y (or rephrased: X op= Y (so an in-place operation))
- std::swap(leftSource, rightSource);
- targetReg = (RegisterID) targetTemp->index;
- break;
-
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- case IR::OpSub:
- break;
-
- default:
- Q_UNREACHABLE();
- return false;
- }
- }
-
- // determine if we have X op= [address]
- if (IR::Temp *lhs = leftSource->asTemp()) {
- if (lhs->kind == IR::Temp::PhysicalRegister && lhs->index == targetTemp->index) {
- if (IR::Temp *rhs = rightSource->asTemp()) {
- if (rhs->kind != IR::Temp::PhysicalRegister) {
- switch (op) {
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpAdd:
- case IR::OpMul:
- inplaceOpWithAddress = true;
- break;
- default:
- break;
- }
- }
- }
- }
- }
- }
-
- // Special cases:
- switch (op) {
- case IR::OpSub:
- if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister
- && targetTemp
- && targetTemp->kind == IR::Temp::PhysicalRegister
- && targetTemp->index == rightSource->asTemp()->index) {
- // X = Y - X -> Tmp = X; X = Y; X -= Tmp
- targetReg = (RegisterID) targetTemp->index;
- as->move(targetReg, JITAssembler::ScratchRegister);
- as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(JITAssembler::ScratchRegister, targetReg);
- } else {
- as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(as->toInt32Register(rightSource, JITAssembler::ScratchRegister), targetReg);
- }
- as->storeInt32(targetReg, target);
- return true;
-
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- if (IR::Const *c = rightSource->asConst()) {
- if ((QV4::Primitive::toUInt32(c->value) & 0x1f) == 0) {
- RegisterID r = as->toInt32Register(leftSource, targetReg);
- as->storeInt32(r, target);
- return true;
- }
- }
- break;
-
- default:
- break;
- }
-
- RegisterID l = as->toInt32Register(leftSource, targetReg);
- if (IR::Const *c = rightSource->asConst()) { // All cases of Y = X op Const
- TrustedImm32 r(int(c->value));
- TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f);
-
- switch (op) {
- case IR::OpBitAnd: as->and32(r, l, targetReg); break;
- case IR::OpBitOr: as->or32 (r, l, targetReg); break;
- case IR::OpBitXor: as->xor32(r, l, targetReg); break;
- case IR::OpAdd: as->add32(r, l, targetReg); break;
- case IR::OpMul: as->mul32(r, l, targetReg); break;
-
- case IR::OpLShift: as->lshift32(l, ur, targetReg); break;
- case IR::OpRShift: as->rshift32(l, ur, targetReg); break;
- case IR::OpURShift: as->urshift32(l, ur, targetReg);
- as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
- return true;
-
- case IR::OpSub: // already handled before
- default: // not handled by this method:
- Q_UNREACHABLE();
- return false;
- }
- } else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddressForReading(JITAssembler::ScratchRegister, rightSource);
- switch (op) {
- case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
- case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
- case IR::OpBitXor: as->xor32(rhsAddr, targetReg); break;
- case IR::OpAdd: as->add32(rhsAddr, targetReg); break;
- case IR::OpMul: as->mul32(rhsAddr, targetReg); break;
- break;
-
- default: // not handled by this method:
- Q_UNREACHABLE();
- return false;
- }
- } else { // All cases of Z = X op Y
- RegisterID r = as->toInt32Register(rightSource, JITAssembler::ScratchRegister);
- switch (op) {
- case IR::OpBitAnd: as->and32(l, r, targetReg); break;
- case IR::OpBitOr: as->or32 (l, r, targetReg); break;
- case IR::OpBitXor: as->xor32(l, r, targetReg); break;
- case IR::OpAdd: as->add32(l, r, targetReg); break;
- case IR::OpMul: as->mul32(l, r, targetReg); break;
-
-#if CPU(X86) || CPU(X86_64)
- // Intel does the & 0x1f on the CPU, so:
- case IR::OpLShift: as->lshift32(l, r, targetReg); break;
- case IR::OpRShift: as->rshift32(l, r, targetReg); break;
- case IR::OpURShift: as->urshift32(l, r, targetReg);
- as->storeUInt32(targetReg, target); // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
- return true;
-#else
- // Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do
- // surprising stuff when shifting over 0 bits.
-#define CHECK_RHS(op) { \
- as->and32(TrustedImm32(0x1f), r, JITAssembler::ScratchRegister); \
- Jump notZero = as->branch32(RelationalCondition::NotEqual, JITAssembler::ScratchRegister, TrustedImm32(0)); \
- as->move(l, targetReg); \
- Jump done = as->jump(); \
- notZero.link(as); \
- op; \
- done.link(as); \
-}
- case IR::OpLShift: CHECK_RHS(as->lshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
- case IR::OpRShift: CHECK_RHS(as->rshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
- case IR::OpURShift:
- CHECK_RHS(as->urshift32(l, JITAssembler::ScratchRegister, targetReg));
- as->storeUInt32(targetReg, target);
- // IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
- return true;
-#undef CHECK_RHS
-#endif
-
- case IR::OpSub: // already handled before
- default: // not handled by this method:
- Q_UNREACHABLE();
- return false;
- }
- }
-
- as->storeInt32(targetReg, target);
- return true;
-}
-
-template <typename JITAssembler>
-inline typename JITAssembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
-{
- if (IR::Temp *t = shouldNotOverlap->asTemp())
- if (t->type == IR::DoubleType)
- if (t->kind == IR::Temp::PhysicalRegister)
- if (t->index == hint)
- return typename JITAssembler::FPRegisterID(hint + 1);
- return typename JITAssembler::FPRegisterID(hint);
-}
-
-template <typename JITAssembler>
-typename JITAssembler::Jump Binop<JITAssembler>::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
-{
- Jump done;
-
- // Try preventing a call for a few common binary operations. This is used in two cases:
- // - no register allocation was performed (not available for the platform, or the IR was
- // not transformed into SSA)
- // - type inference found that either or both operands can be of non-number type, and the
- // register allocator will have prepared for a call (meaning: all registers that do not
- // hold operands are spilled to the stack, which makes them available here)
- // Note: FPGPr0 can still not be used, because uint32->double conversion uses it as a scratch
- // register.
- switch (op) {
- case IR::OpAdd: {
- FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
- Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
- Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
-
- as->addDouble(rReg, lReg);
- as->storeDouble(lReg, target);
- done = as->jump();
-
- if (leftIsNoDbl.isSet())
- leftIsNoDbl.link(as);
- if (rightIsNoDbl.isSet())
- rightIsNoDbl.link(as);
- } break;
- case IR::OpMul: {
- FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
- Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
- Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
-
- as->mulDouble(rReg, lReg);
- as->storeDouble(lReg, target);
- done = as->jump();
-
- if (leftIsNoDbl.isSet())
- leftIsNoDbl.link(as);
- if (rightIsNoDbl.isSet())
- rightIsNoDbl.link(as);
- } break;
- case IR::OpSub: {
- FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
- Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
- Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
-
- as->subDouble(rReg, lReg);
- as->storeDouble(lReg, target);
- done = as->jump();
-
- if (leftIsNoDbl.isSet())
- leftIsNoDbl.link(as);
- if (rightIsNoDbl.isSet())
- rightIsNoDbl.link(as);
- } break;
- case IR::OpDiv: {
- FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
- Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
- Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
-
- as->divDouble(rReg, lReg);
- as->storeDouble(lReg, target);
- done = as->jump();
-
- if (leftIsNoDbl.isSet())
- leftIsNoDbl.link(as);
- if (rightIsNoDbl.isSet())
- rightIsNoDbl.link(as);
- } break;
- default:
- break;
- }
-
- return done;
-}
-
-template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
-#if defined(V4_BOOTSTRAP)
-#if !CPU(ARM_THUMB2)
-template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
-#endif
-#if !CPU(ARM64)
-template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>>;
-#endif
-#endif
-
-} // end of namespace JIT
-} // end of namespace QV4
-
-QT_END_NAMESPACE
-
-
-#endif
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
deleted file mode 100644
index 1b1ab7f24d..0000000000
--- a/src/qml/jit/qv4binop_p.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4BINOP_P_H
-#define QV4BINOP_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 <qv4jsir_p.h>
-#include <qv4isel_masm_p.h>
-#include <qv4assembler_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#if ENABLE(ASSEMBLER)
-
-namespace QV4 {
-namespace JIT {
-
-template <typename JITAssembler>
-struct Binop {
- Binop(JITAssembler *assembler, IR::AluOp operation)
- : as(assembler)
- , op(operation)
- {}
-
- using Jump = typename JITAssembler::Jump;
- using Address = typename JITAssembler::Address;
- using RegisterID = typename JITAssembler::RegisterID;
- using FPRegisterID = typename JITAssembler::FPRegisterID;
- using TrustedImm32 = typename JITAssembler::TrustedImm32;
- using ResultCondition = typename JITAssembler::ResultCondition;
- using RelationalCondition = typename JITAssembler::RelationalCondition;
- using Pointer = typename JITAssembler::Pointer;
- using PointerToValue = typename JITAssembler::PointerToValue;
-
- void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
- void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
- bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
- Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
-
- typedef Jump (Binop::*MemRegOp)(Address, RegisterID);
- typedef Jump (Binop::*ImmRegOp)(TrustedImm32, RegisterID);
-
- struct OpInfo {
- const char *name;
- Runtime::RuntimeMethods fallbackImplementation;
- Runtime::RuntimeMethods contextImplementation;
- MemRegOp inlineMemRegOp;
- ImmRegOp inlineImmRegOp;
- bool needsExceptionCheck;
- };
-
- static const OpInfo operations[IR::LastAluOp + 1];
- static const OpInfo &operation(IR::AluOp operation)
- { return operations[operation]; }
-
- Jump inline_add32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchAdd32(ResultCondition::Overflow, addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- return as->branchAdd32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
-#endif
- }
-
- Jump inline_add32(TrustedImm32 imm, RegisterID reg)
- {
- return as->branchAdd32(ResultCondition::Overflow, imm, reg);
- }
-
- Jump inline_sub32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchSub32(ResultCondition::Overflow, addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- return as->branchSub32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
-#endif
- }
-
- Jump inline_sub32(TrustedImm32 imm, RegisterID reg)
- {
- return as->branchSub32(ResultCondition::Overflow, imm, reg);
- }
-
- Jump inline_mul32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchMul32(JITAssembler::Overflow, addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- return as->branchMul32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
-#endif
- }
-
- Jump inline_mul32(TrustedImm32 imm, RegisterID reg)
- {
- return as->branchMul32(ResultCondition::Overflow, imm, reg, reg);
- }
-
- Jump inline_shl32(Address addr, RegisterID reg)
- {
- as->load32(addr, JITAssembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
- as->lshift32(JITAssembler::ScratchRegister, reg);
- return Jump();
- }
-
- Jump inline_shl32(TrustedImm32 imm, RegisterID reg)
- {
- imm.m_value &= 0x1f;
- as->lshift32(imm, reg);
- return Jump();
- }
-
- Jump inline_shr32(Address addr, RegisterID reg)
- {
- as->load32(addr, JITAssembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
- as->rshift32(JITAssembler::ScratchRegister, reg);
- return Jump();
- }
-
- Jump inline_shr32(TrustedImm32 imm, RegisterID reg)
- {
- imm.m_value &= 0x1f;
- as->rshift32(imm, reg);
- return Jump();
- }
-
- Jump inline_ushr32(Address addr, RegisterID reg)
- {
- as->load32(addr, JITAssembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
- as->urshift32(JITAssembler::ScratchRegister, reg);
- return as->branchTest32(ResultCondition::Signed, reg, reg);
- }
-
- Jump inline_ushr32(TrustedImm32 imm, RegisterID reg)
- {
- imm.m_value &= 0x1f;
- as->urshift32(imm, reg);
- return as->branchTest32(ResultCondition::Signed, reg, reg);
- }
-
- Jump inline_and32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- as->and32(addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- as->and32(JITAssembler::ScratchRegister, reg);
-#endif
- return Jump();
- }
-
- Jump inline_and32(TrustedImm32 imm, RegisterID reg)
- {
- as->and32(imm, reg);
- return Jump();
- }
-
- Jump inline_or32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- as->or32(addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- as->or32(JITAssembler::ScratchRegister, reg);
-#endif
- return Jump();
- }
-
- Jump inline_or32(TrustedImm32 imm, RegisterID reg)
- {
- as->or32(imm, reg);
- return Jump();
- }
-
- Jump inline_xor32(Address addr, RegisterID reg)
- {
-#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- as->xor32(addr, reg);
-#else
- as->load32(addr, JITAssembler::ScratchRegister);
- as->xor32(JITAssembler::ScratchRegister, reg);
-#endif
- return Jump();
- }
-
- Jump inline_xor32(TrustedImm32 imm, RegisterID reg)
- {
- as->xor32(imm, reg);
- return Jump();
- }
-
-
-
- JITAssembler *as;
- IR::AluOp op;
-};
-
-}
-}
-
-#endif
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
deleted file mode 100644
index 4a84d1866f..0000000000
--- a/src/qml/jit/qv4isel_masm.cpp
+++ /dev/null
@@ -1,1688 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 "qv4isel_masm_p.h"
-#include "qv4runtime_p.h"
-#include "qv4lookup_p.h"
-#include "qv4ssa_p.h"
-#include "qv4regalloc_p.h"
-#include "qv4assembler_p.h"
-#include "qv4unop_p.h"
-#include "qv4binop_p.h"
-
-#include <QtCore/QBuffer>
-#include <QtCore/QCoreApplication>
-
-#include <assembler/LinkBuffer.h>
-#include <WTFStubs.h>
-
-#include <iostream>
-
-#if ENABLE(ASSEMBLER)
-
-#if USE(UDIS86)
-# include <udis86.h>
-#endif
-
-using namespace QV4;
-using namespace QV4::JIT;
-
-
-template <typename JITAssembler>
-InstructionSelection<JITAssembler>::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
- : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
- , _block(0)
- , _as(0)
- , compilationUnit(new CompilationUnit)
- , qmlEngine(qmlEngine)
-{
- compilationUnit->codeRefs.resize(module->functions.size());
- module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode;
-}
-
-template <typename JITAssembler>
-InstructionSelection<JITAssembler>::~InstructionSelection()
-{
- delete _as;
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::run(int functionIndex)
-{
- IR::Function *function = irModule->functions[functionIndex];
- qSwap(_function, function);
-
- IR::Optimizer opt(_function);
- opt.run(qmlEngine);
-
- static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC");
- if (JITTargetPlatform::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator regalloc(JITTargetPlatform::getRegisterInfo());
- regalloc.run(_function, opt);
- calculateRegistersToSave(regalloc.usedRegisters());
- } else {
- if (opt.isInSSA())
- // No register allocator available for this platform, or env. var was set, so:
- opt.convertOutOfSSA();
- ConvertTemps().toStackSlots(_function);
- IR::Optimizer::showMeTheCode(_function, "After stack slot allocation");
- calculateRegistersToSave(JITTargetPlatform::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
- }
- BitVector removableJumps = opt.calculateOptionalJumps();
- qSwap(_removableJumps, removableJumps);
-
- JITAssembler* oldAssembler = _as;
- _as = new JITAssembler(jsGenerator, _function, executableAllocator);
- _as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array
- regularRegistersToSave.size(),
- fpRegistersToSave.size());
- _as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
-
- if (JITTargetPlatform::RegisterArgumentCount > 0)
- _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
- else
- _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
-
- _as->initializeLocalVariables();
-
- int lastLine = 0;
- for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
- IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlock(i + 1) : 0;
- _block = _function->basicBlock(i);
- if (_block->isRemoved())
- continue;
- _as->registerBlock(_block, nextBlock);
-
- for (IR::Stmt *s : _block->statements()) {
- if (s->location.isValid()) {
- if (int(s->location.startLine) != lastLine) {
- _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister);
- Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber)));
- _as->store32(TrustedImm32(s->location.startLine), lineAddr);
- lastLine = s->location.startLine;
- }
- }
- visit(s);
- }
- }
-
- if (!_as->exceptionReturnLabel.isSet())
- visitRet(0);
-
- int dummySize;
- JSC::MacroAssemblerCodeRef codeRef =_as->link(&dummySize);
- compilationUnit->codeRefs[functionIndex] = codeRef;
-
- qSwap(_function, function);
- delete _as;
- _as = oldAssembler;
- qSwap(_removableJumps, removableJumps);
-}
-
-template <typename JITAssembler>
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection<JITAssembler>::backendCompileStep()
-{
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
- result.adopt(compilationUnit.take());
- return result;
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
-{
- prepareCallData(args, 0);
-
- if (useFastLookups && func->global) {
- uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(_as, result, callGlobalLookup,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(index),
- baseAddressForCallData());
- } else {
- generateRuntimeCall(_as, result, callActivationProperty,
- JITTargetPlatform::EngineRegister,
- StringToIndex(*func->id),
- baseAddressForCallData());
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
- IR::Member::MemberKind kind,
- int propertyIndex, IR::Expr *result)
-{
- if (kind == IR::Member::MemberOfQmlScopeObject) {
- generateRuntimeCall(_as, result, typeofScopeObjectProperty, JITTargetPlatform::EngineRegister,
- PointerToValue(base),
- TrustedImm32(propertyIndex));
- } else if (kind == IR::Member::MemberOfQmlContextObject) {
- generateRuntimeCall(_as, result, typeofContextObjectProperty,
- JITTargetPlatform::EngineRegister, PointerToValue(base),
- TrustedImm32(propertyIndex));
- } else {
- Q_UNREACHABLE();
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
- IR::Expr *result)
-{
- generateRuntimeCall(_as, result, typeofMember, JITTargetPlatform::EngineRegister,
- PointerToValue(base), StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
- IR::Expr *result)
-{
- generateRuntimeCall(_as, result, typeofElement,
- JITTargetPlatform::EngineRegister,
- PointerToValue(base), PointerToValue(index));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinTypeofName(const QString &name, IR::Expr *result)
-{
- generateRuntimeCall(_as, result, typeofName, JITTargetPlatform::EngineRegister,
- StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
-{
- generateRuntimeCall(_as, result, typeofValue, JITTargetPlatform::EngineRegister,
- PointerToValue(value));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
-{
- generateRuntimeCall(_as, result, deleteMember, JITTargetPlatform::EngineRegister,
- Reference(base), StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
- IR::Expr *result)
-{
- generateRuntimeCall(_as, result, deleteElement, JITTargetPlatform::EngineRegister,
- Reference(base), PointerToValue(index));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &name, IR::Expr *result)
-{
- generateRuntimeCall(_as, result, deleteName, JITTargetPlatform::EngineRegister,
- StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
-{
- _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinThrow(IR::Expr *arg)
-{
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, throwException, JITTargetPlatform::EngineRegister,
- PointerToValue(arg));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinReThrow()
-{
- _as->jumpToExceptionHandler();
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinUnwindException(IR::Expr *result)
-{
- generateRuntimeCall(_as, result, unwindException, JITTargetPlatform::EngineRegister);
-
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinPushCatchScope(const QString &exceptionName)
-{
- generateRuntimeCall(_as, JITAssembler::Void, pushCatchScope, JITTargetPlatform::EngineRegister, StringToIndex(exceptionName));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
-{
- Q_ASSERT(arg);
- Q_ASSERT(result);
-
- generateRuntimeCall(_as, result, foreachIterator, JITTargetPlatform::EngineRegister, PointerToValue(arg));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
-{
- Q_ASSERT(arg);
- Q_ASSERT(result);
-
- generateRuntimeCall(_as, result, foreachNextPropertyName, Reference(arg));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinPushWithScope(IR::Expr *arg)
-{
- Q_ASSERT(arg);
-
- generateRuntimeCall(_as, JITAssembler::Void, pushWithScope, Reference(arg), JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinPopScope()
-{
- generateRuntimeCall(_as, JITAssembler::Void, popScope, JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDeclareVar(bool deletable, const QString &name)
-{
- generateRuntimeCall(_as, JITAssembler::Void, declareVar, JITTargetPlatform::EngineRegister,
- TrustedImm32(deletable), StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
-{
- Q_ASSERT(result);
-
- int length = prepareVariableArguments(args);
- generateRuntimeCall(_as, result, arrayLiteral, JITTargetPlatform::EngineRegister,
- baseAddressForCallArguments(), TrustedImm32(length));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
-{
- Q_ASSERT(result);
-
- QVector<Compiler::JSUnitGenerator::MemberInfo> members;
- int argc = 0;
-
- IR::ExprList *it = keyValuePairs;
- for (int i = 0; i < keyValuePairCount; ++i, it = it->next) {
- QString key = *it->expr->asName()->id;
- it = it->next;
-
- bool isData = it->expr->asConst()->value;
- members.append({ key, !isData });
- it = it->next;
-
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
-
- if (!isData) {
- it = it->next;
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
- }
- }
-
- const int classId = registerJSClass(members);
-
- it = arrayEntries;
- uint arrayValueCount = 0;
- while (it) {
- uint index = it->expr->asConst()->value;
- it = it->next;
-
- bool isData = it->expr->asConst()->value;
- it = it->next;
-
- if (!isData) {
- it = it->next; // getter
- it = it->next; // setter
- continue;
- }
-
- ++arrayValueCount;
-
- // Index
- _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
-
- // Value
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
- it = it->next;
- }
-
- it = arrayEntries;
- uint arrayGetterSetterCount = 0;
- while (it) {
- uint index = it->expr->asConst()->value;
- it = it->next;
-
- bool isData = it->expr->asConst()->value;
- it = it->next;
-
- if (isData) {
- it = it->next; // value
- continue;
- }
-
- ++arrayGetterSetterCount;
-
- // Index
- _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
-
- // Getter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
- it = it->next;
-
- // Setter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
- it = it->next;
- }
-
- generateRuntimeCall(_as, result, objectLiteral, JITTargetPlatform::EngineRegister,
- baseAddressForCallArguments(), TrustedImm32(classId),
- TrustedImm32(arrayValueCount), TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinSetupArgumentObject(IR::Expr *result)
-{
- generateRuntimeCall(_as, result, setupArgumentsObject, JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callBuiltinConvertThisToObject()
-{
- generateRuntimeCall(_as, JITAssembler::Void, convertThisToObject, JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
-{
- Q_ASSERT(value);
-
- prepareCallData(args, 0);
- if (value->asConst())
- generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
- PointerToValue(value),
- baseAddressForCallData());
- else
- generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
- Reference(value),
- baseAddressForCallData());
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
-{
- WriteBarrier::Type barrier;
- Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, temp, &barrier);
- _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ReturnValueRegister);
- _as->loadPtr(Address(JITTargetPlatform::ReturnValueRegister,JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ReturnValueRegister);
- _as->copyValue(addr, Address(JITTargetPlatform::ReturnValueRegister, offsetof(CallData, thisObject)), barrier);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadQmlContext(IR::Expr *temp)
-{
- generateRuntimeCall(_as, temp, getQmlContext, JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadQmlImportedScripts(IR::Expr *temp)
-{
- generateRuntimeCall(_as, temp, getQmlImportedScripts, JITTargetPlatform::EngineRegister);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadQmlSingleton(const QString &name, IR::Expr *temp)
-{
- generateRuntimeCall(_as, temp, getQmlSingleton, JITTargetPlatform::EngineRegister, StringToIndex(name));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::Expr *target)
-{
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp->type == IR::DoubleType) {
- Q_ASSERT(sourceConst->type == IR::DoubleType);
- _as->toDoubleRegister(sourceConst, (FPRegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::SInt32Type) {
- Q_ASSERT(sourceConst->type == IR::SInt32Type);
- _as->toInt32Register(sourceConst, (RegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::UInt32Type) {
- Q_ASSERT(sourceConst->type == IR::UInt32Type);
- _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
- } else if (targetTemp->type == IR::BoolType) {
- Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(TrustedImm32(convertToValue<Primitive>(sourceConst).int_32()),
- (RegisterID) targetTemp->index);
- } else {
- Q_UNREACHABLE();
- }
- return;
- }
- }
-
- _as->storeValue(convertToValue<typename JITAssembler::TargetPrimitive>(sourceConst), target);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr *target)
-{
- Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
- _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
- WriteBarrier::Type barrier;
- Pointer destAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, target, &barrier);
- JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr, barrier);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
-{
- int id = registerRegExp(sourceRegexp);
- generateRuntimeCall(_as, target, regexpLiteral, JITTargetPlatform::EngineRegister, TrustedImm32(id));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::getActivationProperty(const IR::Name *name, IR::Expr *target)
-{
- if (useFastLookups && name->global) {
- uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(target, index, offsetof(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
- return;
- }
- generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::setActivationProperty(IR::Expr *source, const QString &targetName)
-{
- // ### should use a lookup call here
- generateRuntimeCall(_as, JITAssembler::Void, setActivationProperty,
- JITTargetPlatform::EngineRegister, StringToIndex(targetName), PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::initClosure(IR::Closure *closure, IR::Expr *target)
-{
- int id = closure->value;
- generateRuntimeCall(_as, target, closure, JITTargetPlatform::EngineRegister, TrustedImm32(id));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
-{
- if (useFastLookups) {
- uint index = registerGetterLookup(name);
- generateLookupCall(target, index, offsetof(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
- } else {
- generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister,
- PointerToValue(base), StringToIndex(name));
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
-{
- if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(_as, target, getQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
- else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(_as, target, getQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
- else if (kind == IR::Member::MemberOfIdObjectsArray)
- generateRuntimeCall(_as, target, getQmlIdObject, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index));
- else
- Q_ASSERT(false);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
-{
- if (attachedPropertiesId != 0)
- generateRuntimeCall(_as, target, getQmlAttachedProperty, JITTargetPlatform::EngineRegister, TrustedImm32(attachedPropertiesId), TrustedImm32(propertyIndex));
- else if (isSingleton)
- generateRuntimeCall(_as, target, getQmlSingletonQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
- TrustedImm32(captureRequired));
- else
- generateRuntimeCall(_as, target, getQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
- TrustedImm32(captureRequired));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr *targetBase,
- const QString &targetName)
-{
- if (useFastLookups) {
- uint index = registerSetterLookup(targetName);
- generateLookupCall(JITAssembler::Void, index, offsetof(QV4::Lookup, setter),
- JITTargetPlatform::EngineRegister,
- PointerToValue(targetBase),
- PointerToValue(source));
- } else {
- generateRuntimeCall(_as, JITAssembler::Void, setProperty, JITTargetPlatform::EngineRegister,
- PointerToValue(targetBase), StringToIndex(targetName),
- PointerToValue(source));
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
-{
- if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(_as, JITAssembler::Void, setQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
- TrustedImm32(propertyIndex), PointerToValue(source));
- else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(_as, JITAssembler::Void, setQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
- TrustedImm32(propertyIndex), PointerToValue(source));
- else
- Q_ASSERT(false);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
-{
- generateRuntimeCall(_as, JITAssembler::Void, setQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
- TrustedImm32(propertyIndex), PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
-{
- if (0 && useFastLookups) {
- uint lookup = registerIndexedGetterLookup();
- generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter),
- JITTargetPlatform::EngineRegister,
- PointerToValue(base),
- PointerToValue(index));
- return;
- }
-
- generateRuntimeCall(_as, target, getElement, JITTargetPlatform::EngineRegister,
- PointerToValue(base), PointerToValue(index));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
-{
- if (0 && useFastLookups) {
- uint lookup = registerIndexedSetterLookup();
- generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter),
- JITTargetPlatform::EngineRegister,
- PointerToValue(targetBase), PointerToValue(targetIndex),
- PointerToValue(source));
- return;
- }
- generateRuntimeCall(_as, JITAssembler::Void, setElement, JITTargetPlatform::EngineRegister,
- PointerToValue(targetBase), PointerToValue(targetIndex),
- PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *sourceTemp = source->asTemp();
- IR::Temp *targetTemp = target->asTemp();
-
- if (sourceTemp && targetTemp && *sourceTemp == *targetTemp)
- return;
- if (IR::ArgLocal *sal = source->asArgLocal())
- if (IR::ArgLocal *tal = target->asArgLocal())
- if (*sal == *tal)
- return;
-
- if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- if (sourceTemp->type == IR::DoubleType)
- _as->moveDouble((FPRegisterID) sourceTemp->index,
- (FPRegisterID) targetTemp->index);
- else
- _as->move((RegisterID) sourceTemp->index,
- (RegisterID) targetTemp->index);
- return;
- } else {
- switch (sourceTemp->type) {
- case IR::DoubleType:
- _as->storeDouble((FPRegisterID) sourceTemp->index, target);
- break;
- case IR::SInt32Type:
- _as->storeInt32((RegisterID) sourceTemp->index, target);
- break;
- case IR::UInt32Type:
- _as->storeUInt32((RegisterID) sourceTemp->index, target);
- break;
- case IR::BoolType:
- _as->storeBool((RegisterID) sourceTemp->index, target);
- break;
- default:
- Q_ASSERT(!"Unreachable");
- break;
- }
- return;
- }
- } else if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- switch (targetTemp->type) {
- case IR::DoubleType:
- Q_ASSERT(source->type == IR::DoubleType);
- _as->toDoubleRegister(source, (FPRegisterID) targetTemp->index);
- return;
- case IR::BoolType:
- Q_ASSERT(source->type == IR::BoolType);
- _as->toInt32Register(source, (RegisterID) targetTemp->index);
- return;
- case IR::SInt32Type:
- Q_ASSERT(source->type == IR::SInt32Type);
- _as->toInt32Register(source, (RegisterID) targetTemp->index);
- return;
- case IR::UInt32Type:
- Q_ASSERT(source->type == IR::UInt32Type);
- _as->toUInt32Register(source, (RegisterID) targetTemp->index);
- return;
- default:
- Q_ASSERT(!"Unreachable");
- break;
- }
- }
-
- WriteBarrier::Type barrier;
- Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrier);
- // The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(addr, source, JITTargetPlatform::ScratchRegister, barrier);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *sourceTemp = source->asTemp();
- IR::Temp *targetTemp = target->asTemp();
-
- if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
- Q_ASSERT(sourceTemp->type == targetTemp->type);
-
- if (sourceTemp->type == IR::DoubleType) {
- _as->moveDouble((FPRegisterID) targetTemp->index, JITTargetPlatform::FPGpr0);
- _as->moveDouble((FPRegisterID) sourceTemp->index,
- (FPRegisterID) targetTemp->index);
- _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) sourceTemp->index);
- } else {
- _as->swap((RegisterID) sourceTemp->index,
- (RegisterID) targetTemp->index);
- }
- return;
- }
- } else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- // Note: a swap for two stack-slots can involve different types.
- WriteBarrier::Type barrierForSource, barrierForTarget;
- Pointer sAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, source, &barrierForSource);
- Pointer tAddr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrierForTarget);
- _as->loadRawValue(sAddr, JITTargetPlatform::FPGpr0);
- _as->loadRawValue(tAddr, JITTargetPlatform::FPGpr1);
- _as->storeRawValue(JITTargetPlatform::FPGpr1, sAddr, barrierForSource);
- _as->storeRawValue(JITTargetPlatform::FPGpr0, tAddr, barrierForTarget);
- return;
- }
- }
-
- IR::Expr *memExpr = !sourceTemp || sourceTemp->kind == IR::Temp::StackSlot ? source : target;
- IR::Temp *regTemp = sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister ? sourceTemp
- : targetTemp;
- Q_ASSERT(memExpr);
- Q_ASSERT(regTemp);
-
- WriteBarrier::Type barrier;
- Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, memExpr, &barrier);
- if (regTemp->type == IR::DoubleType) {
- _as->loadDouble(addr, JITTargetPlatform::FPGpr0);
- _as->storeDouble((FPRegisterID) regTemp->index, addr, barrier);
- _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
- } else if (regTemp->type == IR::UInt32Type) {
- _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
- _as->storeUInt32((RegisterID) regTemp->index, addr, barrier);
- _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
- } else {
- _as->load32(addr, JITTargetPlatform::ScratchRegister);
- _as->store32((RegisterID) regTemp->index, addr);
- if (regTemp->type != memExpr->type) {
- addr.offset += 4;
- quint32 tag;
- switch (regTemp->type) {
- case IR::BoolType:
- tag = quint32(JITAssembler::ValueTypeInternal::Boolean);
- break;
- case IR::SInt32Type:
- tag = quint32(JITAssembler::ValueTypeInternal::Integer);
- break;
- default:
- tag = 31337; // bogus value
- Q_UNREACHABLE();
- }
- _as->store32(TrustedImm32(tag), addr);
- _as->emitWriteBarrier(addr, barrier);
- }
- _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
- }
-}
-
-#define setOp(op, opName, operation) \
- do { \
- op = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \
- needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
- } while (0)
-#define setOpContext(op, opName, operation) \
- do { \
- opContext = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \
- needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
- } while (0)
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
-{
- QV4::JIT::Unop<JITAssembler> unop(_as, oper);
- unop.generate(source, target);
-}
-
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
-{
- QV4::JIT::Binop<JITAssembler> binop(_as, oper);
- binop.generate(leftSource, rightSource, target);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
-{
- prepareCallData(args, base);
-
- if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(_as, result, callQmlScopeObjectProperty,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(propertyIndex),
- baseAddressForCallData());
- else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(_as, result, callQmlContextObjectProperty,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(propertyIndex),
- baseAddressForCallData());
- else
- Q_ASSERT(false);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Expr *result)
-{
- Q_ASSERT(base != 0);
-
- prepareCallData(args, base);
-
- if (useFastLookups) {
- uint index = registerGetterLookup(name);
- generateRuntimeCall(_as, result, callPropertyLookup,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(index),
- baseAddressForCallData());
- } else {
- generateRuntimeCall(_as, result, callProperty, JITTargetPlatform::EngineRegister,
- StringToIndex(name),
- baseAddressForCallData());
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Expr *result)
-{
- Q_ASSERT(base != 0);
-
- prepareCallData(args, base);
- generateRuntimeCall(_as, result, callElement, JITTargetPlatform::EngineRegister,
- PointerToValue(index),
- baseAddressForCallData());
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertType(IR::Expr *source, IR::Expr *target)
-{
- switch (target->type) {
- case IR::DoubleType:
- convertTypeToDouble(source, target);
- break;
- case IR::BoolType:
- convertTypeToBool(source, target);
- break;
- case IR::SInt32Type:
- convertTypeToSInt32(source, target);
- break;
- case IR::UInt32Type:
- convertTypeToUInt32(source, target);
- break;
- default:
- convertTypeSlowPath(source, target);
- break;
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
-{
- Q_ASSERT(target->type != IR::BoolType);
-
- if (target->type & IR::NumberType)
- unop(IR::OpUPlus, source, target);
- else
- copyValue(source, target);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
-{
- switch (source->type) {
- case IR::SInt32Type:
- case IR::BoolType:
- case IR::NullType:
- convertIntToDouble(source, target);
- break;
- case IR::UInt32Type:
- convertUIntToDouble(source, target);
- break;
- case IR::UndefinedType:
- _as->loadDouble(_as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
- _as->storeDouble(JITTargetPlatform::FPGpr0, target);
- break;
- case IR::StringType:
- case IR::VarType: {
- // load the tag:
- Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
- tagAddr.offset += 4;
- _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
-
- // check if it's an int32:
- Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
- convertIntToDouble(source, target);
- Jump intDone = _as->jump();
-
- // not an int, check if it's NOT a double:
- isNoInt.link(_as);
- Jump isDbl = _as->generateIsDoubleCheck(JITTargetPlatform::ScratchRegister);
-
- generateRuntimeCall(_as, target, toDouble, PointerToValue(source));
- Jump noDoubleDone = _as->jump();
-
- // it is a double:
- isDbl.link(_as);
- Pointer addr2 = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
- } else {
- _as->loadDouble(addr2, (FPRegisterID) targetTemp->index);
- }
-
- noDoubleDone.link(_as);
- intDone.link(_as);
- } break;
- default:
- convertTypeSlowPath(source, target);
- break;
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *sourceTemp = source->asTemp();
- switch (source->type) {
- case IR::SInt32Type:
- case IR::UInt32Type:
- convertIntToBool(source, target);
- break;
- case IR::DoubleType: {
- // The source is in a register if the register allocator is used. If the register
- // allocator was not used, then that means that we can use any register for to
- // load the double into.
- FPRegisterID reg;
- if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister)
- reg = (FPRegisterID) sourceTemp->index;
- else
- reg = _as->toDoubleRegister(source, (FPRegisterID) 1);
- Jump nonZero = _as->branchDoubleNonZero(reg, JITTargetPlatform::FPGpr0);
-
- // it's 0, so false:
- _as->storeBool(false, target);
- Jump done = _as->jump();
-
- // it's non-zero, so true:
- nonZero.link(_as);
- _as->storeBool(true, target);
-
- // done:
- done.link(_as);
- } break;
- case IR::UndefinedType:
- case IR::NullType:
- _as->storeBool(false, target);
- break;
- case IR::StringType:
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
- PointerToValue(source));
- _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
- Q_FALLTHROUGH();
- case IR::VarType:
- default:
- Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
- Pointer tagAddr = addr;
- tagAddr.offset += 4;
- _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
-
- // checkif it's a bool:
- Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
- _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
- Jump boolDone = _as->jump();
- // check if it's an int32:
- notBool.link(_as);
- Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
- _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
- Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(0));
- _as->move(TrustedImm32(1), JITTargetPlatform::ReturnValueRegister);
- Jump intDone = _as->jump();
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
- PointerToValue(source));
-
- isZero.link(_as);
- intDone.link(_as);
- boolDone.link(_as);
- _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
-
- break;
- }
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
-{
- switch (source->type) {
- case IR::VarType: {
- JITAssembler::RegisterSizeDependentOps::convertVarToSInt32(_as, source, target);
- } break;
- case IR::DoubleType: {
- Jump success =
- _as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
- JITTargetPlatform::ReturnValueRegister,
- BranchTruncateType::BranchIfTruncateSuccessful);
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToInt,
- PointerToValue(source));
- success.link(_as);
- _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
- } break;
- case IR::UInt32Type:
- _as->storeInt32(_as->toUInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
- break;
- case IR::NullType:
- case IR::UndefinedType:
- _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
- _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
- break;
- case IR::BoolType:
- _as->storeInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
- break;
- case IR::StringType:
- default:
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
- _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
- _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
- break;
- } // switch (source->type)
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
-{
- switch (source->type) {
- case IR::VarType: {
- // load the tag:
- Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
- tagAddr.offset += 4;
- _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
-
- // check if it's an int32:
- Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
- Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
- _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
- Jump intDone = _as->jump();
-
- // not an int:
- isNoInt.link(_as);
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
- _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
- _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
-
- intDone.link(_as);
- } break;
- case IR::DoubleType: {
- FPRegisterID reg = _as->toDoubleRegister(source);
- Jump success =
- _as->branchTruncateDoubleToUint32(reg, JITTargetPlatform::ReturnValueRegister,
- BranchTruncateType::BranchIfTruncateSuccessful);
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToUInt,
- PointerToValue(source));
- success.link(_as);
- _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
- } break;
- case IR::NullType:
- case IR::UndefinedType:
- _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
- _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
- break;
- case IR::StringType:
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
- PointerToValue(source));
- _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
- break;
- case IR::SInt32Type:
- case IR::BoolType:
- _as->storeUInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
- break;
- default:
- break;
- } // switch (source->type)
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
-{
- Q_ASSERT(func != 0);
- prepareCallData(args, 0);
-
- if (useFastLookups && func->global) {
- uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(_as, result, constructGlobalLookup,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(index), baseAddressForCallData());
- return;
- }
-
- generateRuntimeCall(_as, result, constructActivationProperty,
- JITTargetPlatform::EngineRegister,
- StringToIndex(*func->id),
- baseAddressForCallData());
-}
-
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
-{
- prepareCallData(args, base);
- if (useFastLookups) {
- uint index = registerGetterLookup(name);
- generateRuntimeCall(_as, result, constructPropertyLookup,
- JITTargetPlatform::EngineRegister,
- TrustedImm32(index),
- baseAddressForCallData());
- return;
- }
-
- generateRuntimeCall(_as, result, constructProperty, JITTargetPlatform::EngineRegister,
- StringToIndex(name),
- baseAddressForCallData());
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
-{
- Q_ASSERT(value != 0);
-
- prepareCallData(args, 0);
- generateRuntimeCall(_as, result, constructValue,
- JITTargetPlatform::EngineRegister,
- Reference(value),
- baseAddressForCallData());
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::visitJump(IR::Jump *s)
-{
- if (!_removableJumps.at(_block->index()))
- _as->jumpToBlock(_block, s->target);
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
-{
- IR::Temp *t = s->cond->asTemp();
- if (t || s->cond->asArgLocal()) {
- RegisterID reg;
- if (t && t->kind == IR::Temp::PhysicalRegister) {
- Q_ASSERT(t->type == IR::BoolType);
- reg = (RegisterID) t->index;
- } else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
- reg = JITTargetPlatform::ReturnValueRegister;
- _as->toInt32Register(t, reg);
- } else {
- Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond);
- Address tag = temp;
- tag.offset += QV4::Value::tagOffset();
- Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
-
- Address data = temp;
- data.offset += QV4::Value::valueOffset();
- _as->load32(data, JITTargetPlatform::ReturnValueRegister);
- Jump testBoolean = _as->jump();
-
- booleanConversion.link(_as);
- reg = JITTargetPlatform::ReturnValueRegister;
- generateRuntimeCall(_as, reg, toBoolean, Reference(s->cond));
-
- testBoolean.link(_as);
- }
-
- _as->generateCJumpOnNonZero(reg, _block, s->iftrue, s->iffalse);
- return;
- } else if (IR::Const *c = s->cond->asConst()) {
- // TODO: SSA optimization for constant condition evaluation should remove this.
- // See also visitCJump() in RegAllocInfo.
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
- PointerToValue(c));
- _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
- return;
- } else if (IR::Binop *b = s->cond->asBinop()) {
- if (b->left->type == IR::DoubleType && b->right->type == IR::DoubleType
- && visitCJumpDouble(b->op, b->left, b->right, s->iftrue, s->iffalse))
- return;
-
- if (b->left->type == IR::SInt32Type && b->right->type == IR::SInt32Type
- && visitCJumpSInt32(b->op, b->left, b->right, s->iftrue, s->iffalse))
- return;
-
- if (b->op == IR::OpStrictEqual || b->op == IR::OpStrictNotEqual) {
- visitCJumpStrict(b, s->iftrue, s->iffalse);
- return;
- }
- if (b->op == IR::OpEqual || b->op == IR::OpNotEqual) {
- visitCJumpEqual(b, s->iftrue, s->iffalse);
- return;
- }
-
- typename JITAssembler::RuntimeCall op;
- typename JITAssembler::RuntimeCall opContext;
- const char *opName = 0;
- bool needsExceptionCheck;
- switch (b->op) {
- default: Q_UNREACHABLE(); Q_ASSERT(!"todo"); break;
- case IR::OpGt: setOp(op, opName, compareGreaterThan); break;
- case IR::OpLt: setOp(op, opName, compareLessThan); break;
- case IR::OpGe: setOp(op, opName, compareGreaterEqual); break;
- case IR::OpLe: setOp(op, opName, compareLessEqual); break;
- case IR::OpEqual: setOp(op, opName, compareEqual); break;
- case IR::OpNotEqual: setOp(op, opName, compareNotEqual); break;
- case IR::OpStrictEqual: setOp(op, opName, compareStrictEqual); break;
- case IR::OpStrictNotEqual: setOp(op, opName, compareStrictNotEqual); break;
- case IR::OpInstanceof: setOpContext(op, opName, compareInstanceof); break;
- case IR::OpIn: setOpContext(op, opName, compareIn); break;
- } // switch
-
- // TODO: in SSA optimization, do constant expression evaluation.
- // The case here is, for example:
- // if (true === true) .....
- // Of course, after folding the CJUMP to a JUMP, dead-code (dead-basic-block)
- // elimination (which isn't there either) would remove the whole else block.
- if (opContext.isValid())
- _as->generateFunctionCallImp(needsExceptionCheck,
- JITTargetPlatform::ReturnValueRegister, opName, opContext,
- JITTargetPlatform::EngineRegister,
- PointerToValue(b->left),
- PointerToValue(b->right));
- else
- _as->generateFunctionCallImp(needsExceptionCheck,
- JITTargetPlatform::ReturnValueRegister, opName, op,
- PointerToValue(b->left),
- PointerToValue(b->right));
-
- _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
- return;
- }
- Q_UNREACHABLE();
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::visitRet(IR::Ret *s)
-{
- _as->returnFromFunction(s, regularRegistersToSave, fpRegistersToSave);
-}
-
-template <typename JITAssembler>
-int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* args)
-{
- int argc = 0;
- for (IR::ExprList *it = args; it; it = it->next) {
- ++argc;
- }
-
- int i = 0;
- for (IR::ExprList *it = args; it; it = it->next, ++i) {
- IR::Expr *arg = it->expr;
- Q_ASSERT(arg != 0);
- Pointer dst(_as->stackLayout().argumentAddressForCall(i));
- if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
- else
- _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
- }
-
- return argc;
-}
-
-template <typename JITAssembler>
-int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
-{
- int argc = 0;
- for (IR::ExprList *it = args; it; it = it->next) {
- ++argc;
- }
-
- Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag));
- _as->store32(TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)), p);
- p = _as->stackLayout().callDataAddress(offsetof(CallData, argc));
- _as->store32(TrustedImm32(argc), p);
- p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject));
- if (!thisObject)
- _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p, WriteBarrier::NoBarrier);
- else
- _as->copyValue(p, thisObject, WriteBarrier::NoBarrier);
-
- int i = 0;
- for (IR::ExprList *it = args; it; it = it->next, ++i) {
- IR::Expr *arg = it->expr;
- Q_ASSERT(arg != 0);
- Pointer dst(_as->stackLayout().argumentAddressForCall(i));
- if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
- else
- _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
- }
- return argc;
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::calculateRegistersToSave(const RegisterInformation &used)
-{
- regularRegistersToSave.clear();
- fpRegistersToSave.clear();
-
- for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
- if (JITTargetPlatform::gotRegister != -1 && ri.isRegularRegister() && ri.reg<RegisterID>() == JITTargetPlatform::gotRegister) {
- regularRegistersToSave.append(ri);
- continue;
- }
- if (ri.isCallerSaved())
- continue;
- if (ri.isRegularRegister()) {
- if (ri.isPredefined() || used.contains(ri))
- regularRegistersToSave.append(ri);
- } else {
- Q_ASSERT(ri.isFloatingPoint());
- if (ri.isPredefined() || used.contains(ri))
- fpRegistersToSave.append(ri);
- }
- }
-}
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-bool operator==(const Primitive &v1, const Primitive &v2)
-{
- return v1.rawValue() == v2.rawValue();
-}
-} // QV4 namespace
-QT_END_NAMESPACE
-
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
- IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
-{
- if (_as->nextBlock() == iftrue) {
- Jump target = _as->branchDouble(true, op, left, right);
- _as->addPatch(iffalse, target);
- } else {
- Jump target = _as->branchDouble(false, op, left, right);
- _as->addPatch(iftrue, target);
- _as->jumpToBlock(_block, iffalse);
- }
- return true;
-}
-
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
- IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
-{
- if (_as->nextBlock() == iftrue) {
- Jump target = _as->branchInt32(true, op, left, right);
- _as->addPatch(iffalse, target);
- } else {
- Jump target = _as->branchInt32(false, op, left, right);
- _as->addPatch(iftrue, target);
- _as->jumpToBlock(_block, iffalse);
- }
- return true;
-}
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual);
-
- if (visitCJumpStrictNull(binop, trueBlock, falseBlock))
- return;
- if (visitCJumpStrictUndefined(binop, trueBlock, falseBlock))
- return;
- if (visitCJumpStrictBool(binop, trueBlock, falseBlock))
- return;
-
- IR::Expr *left = binop->left;
- IR::Expr *right = binop->right;
-
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareStrictEqual,
- PointerToValue(left), PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
- JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
- _block, trueBlock, falseBlock);
-}
-
-// Only load the non-null temp.
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- IR::Expr *varSrc = 0;
- if (binop->left->type == IR::VarType && binop->right->type == IR::NullType)
- varSrc = binop->left;
- else if (binop->left->type == IR::NullType && binop->right->type == IR::VarType)
- varSrc = binop->right;
- if (!varSrc)
- return false;
-
- if (varSrc->asTemp() && varSrc->asTemp()->kind == IR::Temp::PhysicalRegister) {
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- if (IR::Const *c = varSrc->asConst()) {
- if (c->type == IR::NullType)
- _as->jumpToBlock(_block, trueBlock);
- else
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
- tagAddr.offset += 4;
- const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
- _as->load32(tagAddr, tagReg);
-
- RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
- : RelationalCondition::NotEqual;
- const TrustedImm32 tag{quint32(JITAssembler::ValueTypeInternal::Null)};
- _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
- return true;
-}
-
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpStrictUndefined(IR::Binop *binop,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- IR::Expr *varSrc = 0;
- if (binop->left->type == IR::VarType && binop->right->type == IR::UndefinedType)
- varSrc = binop->left;
- else if (binop->left->type == IR::UndefinedType && binop->right->type == IR::VarType)
- varSrc = binop->right;
- if (!varSrc)
- return false;
-
- if (varSrc->asTemp() && varSrc->asTemp()->kind == IR::Temp::PhysicalRegister) {
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- if (IR::Const *c = varSrc->asConst()) {
- if (c->type == IR::UndefinedType)
- _as->jumpToBlock(_block, trueBlock);
- else
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
- : RelationalCondition::NotEqual;
- const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
- _as->generateCJumpOnUndefined(cond, varSrc, JITTargetPlatform::ScratchRegister, tagReg, _block, trueBlock, falseBlock);
- return true;
-}
-
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- IR::Expr *boolSrc = 0, *otherSrc = 0;
- if (binop->left->type == IR::BoolType) {
- boolSrc = binop->left;
- otherSrc = binop->right;
- } else if (binop->right->type == IR::BoolType) {
- boolSrc = binop->right;
- otherSrc = binop->left;
- } else {
- // neither operands are statically typed as bool, so bail out.
- return false;
- }
- if (otherSrc->type == IR::UnknownType) {
- // Ok, we really need to call into the runtime.
- // (This case doesn't happen when the optimizer ran, because everything will be typed (yes,
- // possibly as "var" meaning anything), but it does happen for $0===true, which is generated
- // for things where the optimizer didn't run (like functions with a try block).)
- return false;
- }
-
- RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
- : RelationalCondition::NotEqual;
-
- if (otherSrc->type == IR::BoolType) { // both are boolean
- RegisterID one = _as->toBoolRegister(boolSrc, JITTargetPlatform::ReturnValueRegister);
- RegisterID two = _as->toBoolRegister(otherSrc, JITTargetPlatform::ScratchRegister);
- _as->generateCJumpOnCompare(cond, one, two, _block, trueBlock, falseBlock);
- return true;
- }
-
- if (otherSrc->type != IR::VarType) {
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- Pointer otherAddr = _as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, otherSrc);
- otherAddr.offset += 4; // tag address
-
- // check if the tag of the var operand is indicates 'boolean'
- _as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
- Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
- if (binop->op == IR::OpStrictEqual)
- _as->addPatch(falseBlock, noBool);
- else
- _as->addPatch(trueBlock, noBool);
-
- // ok, both are boolean, so let's load them and compare them.
- otherAddr.offset -= 4; // int_32 address
- _as->load32(otherAddr, JITTargetPlatform::ReturnValueRegister);
- RegisterID boolReg = _as->toBoolRegister(boolSrc, JITTargetPlatform::ScratchRegister);
- _as->generateCJumpOnCompare(cond, boolReg, JITTargetPlatform::ReturnValueRegister, _block, trueBlock,
- falseBlock);
- return true;
-}
-
-template <typename JITAssembler>
-bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- Q_ASSERT(nullOrUndef == IR::NullType || nullOrUndef == IR::UndefinedType);
-
- IR::Expr *varSrc = 0;
- if (binop->left->type == IR::VarType && binop->right->type == nullOrUndef)
- varSrc = binop->left;
- else if (binop->left->type == nullOrUndef && binop->right->type == IR::VarType)
- varSrc = binop->right;
- if (!varSrc)
- return false;
-
- if (varSrc->asTemp() && varSrc->asTemp()->kind == IR::Temp::PhysicalRegister) {
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- if (IR::Const *c = varSrc->asConst()) {
- if (c->type == nullOrUndef)
- _as->jumpToBlock(_block, trueBlock);
- else
- _as->jumpToBlock(_block, falseBlock);
- return true;
- }
-
- Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
- tagAddr.offset += 4;
- const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
- _as->load32(tagAddr, tagReg);
-
- if (binop->op == IR::OpNotEqual)
- qSwap(trueBlock, falseBlock);
- Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Null)));
- Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
- tagAddr.offset -= 4;
- _as->load32(tagAddr, tagReg);
- Jump isNotUndefinedValue = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(0));
- _as->addPatch(trueBlock, isNull);
- _as->addPatch(falseBlock, isNotUndefinedTag);
- _as->addPatch(falseBlock, isNotUndefinedValue);
- _as->jumpToBlock(_block, trueBlock);
-
- return true;
-}
-
-
-template <typename JITAssembler>
-void InstructionSelection<JITAssembler>::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- Q_ASSERT(binop->op == IR::OpEqual || binop->op == IR::OpNotEqual);
-
- if (visitCJumpNullUndefined(IR::NullType, binop, trueBlock, falseBlock))
- return;
-
- IR::Expr *left = binop->left;
- IR::Expr *right = binop->right;
-
- generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareEqual,
- PointerToValue(left), PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
- JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
- _block, trueBlock, falseBlock);
-}
-
-template <typename JITAssembler>
-QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createUnitForLoading()
-{
- QQmlRefPointer<CompiledData::CompilationUnit> result;
- result.adopt(new JIT::CompilationUnit);
- return result;
-}
-
-#endif // ENABLE(ASSEMBLER)
-
-QT_BEGIN_NAMESPACE
-namespace QV4 { namespace JIT {
-#if ENABLE(ASSEMBLER)
-template class Q_QML_EXPORT InstructionSelection<>;
-template class Q_QML_EXPORT ISelFactory<>;
-#endif
-
-#if defined(V4_BOOTSTRAP)
-
-Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
-{
- Q_UNUSED(architecture)
-#if ENABLE(ASSEMBLER)
- using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
- using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
-
- if (architecture == QLatin1String("arm"))
- return new ISelFactory<ARMv7CrossAssembler>;
- else if (architecture == QLatin1String("arm64"))
- return new ISelFactory<ARM64CrossAssembler>;
-
- QString hostArch;
-#if CPU(ARM_THUMB2)
- hostArch = QStringLiteral("arm");
-#elif CPU(MIPS)
- hostArch = QStringLiteral("mips");
-#elif CPU(X86)
- hostArch = QStringLiteral("i386");
-#elif CPU(X86_64)
- hostArch = QStringLiteral("x86_64");
-#endif
- if (!hostArch.isEmpty() && architecture == hostArch)
- return new ISelFactory<>;
-#endif // ENABLE(ASSEMBLER)
-
- return nullptr;
-}
-
-#endif
-} }
-QT_END_NAMESPACE
-
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
deleted file mode 100644
index 7019a117a2..0000000000
--- a/src/qml/jit/qv4isel_masm_p.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4ISEL_MASM_P_H
-#define QV4ISEL_MASM_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/qv4global_p.h"
-#include "private/qv4jsir_p.h"
-#include "private/qv4isel_p.h"
-#include "private/qv4isel_util_p.h"
-#include "private/qv4util_p.h"
-#include "private/qv4value_p.h"
-#include "private/qv4lookup_p.h"
-
-#include <QtCore/QHash>
-#include <QtCore/QStack>
-#include <config.h>
-#include <wtf/Vector.h>
-
-#include "qv4assembler_p.h"
-
-#if ENABLE(ASSEMBLER)
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
-class Q_QML_EXPORT InstructionSelection:
- protected IR::IRDecoder,
- public EvalInstructionSelection
-{
-public:
- InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory);
- ~InstructionSelection();
-
- void run(int functionIndex) override;
-
-protected:
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> backendCompileStep() override;
-
- void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) override;
- void callBuiltinTypeofQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::Expr *result) override;
- void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) override;
- void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) override;
- void callBuiltinTypeofName(const QString &name, IR::Expr *result) override;
- void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) override;
- void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) override;
- void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) override;
- void callBuiltinDeleteName(const QString &name, IR::Expr *result) override;
- void callBuiltinDeleteValue(IR::Expr *result) override;
- void callBuiltinThrow(IR::Expr *arg) override;
- void callBuiltinReThrow() override;
- void callBuiltinUnwindException(IR::Expr *) override;
- void callBuiltinPushCatchScope(const QString &exceptionName) override;
- void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) override;
- void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) override;
- void callBuiltinPushWithScope(IR::Expr *arg) override;
- void callBuiltinPopScope() override;
- void callBuiltinDeclareVar(bool deletable, const QString &name) override;
- void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) override;
- void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) override;
- void callBuiltinSetupArgumentObject(IR::Expr *result) override;
- void callBuiltinConvertThisToObject() override;
- void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override;
- void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) override;
- void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) override;
- void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) override;
- void convertType(IR::Expr *source, IR::Expr *target) override;
- void loadThisObject(IR::Expr *temp) override;
- void loadQmlContext(IR::Expr *target) override;
- void loadQmlImportedScripts(IR::Expr *target) override;
- void loadQmlSingleton(const QString &name, IR::Expr *target) override;
- void loadConst(IR::Const *sourceConst, IR::Expr *target) override;
- void loadString(const QString &str, IR::Expr *target) override;
- void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) override;
- void getActivationProperty(const IR::Name *name, IR::Expr *target) override;
- void setActivationProperty(IR::Expr *source, const QString &targetName) override;
- void initClosure(IR::Closure *closure, IR::Expr *target) override;
- void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) override;
- void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target) override;
- void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) override;
- void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) override;
- void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) override;
- void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) override;
- void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) override;
- void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) override;
- void copyValue(IR::Expr *source, IR::Expr *target) override;
- void swapValues(IR::Expr *source, IR::Expr *target) override;
- void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target) override;
- void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) override;
-
- using Address = typename JITAssembler::Address;
- using Pointer = typename JITAssembler::Pointer;
- using PointerToValue = typename JITAssembler::PointerToValue;
- using RegisterID = typename JITAssembler::RegisterID;
- using FPRegisterID = typename JITAssembler::FPRegisterID;
- using ResultCondition = typename JITAssembler::ResultCondition;
- using TrustedImm32 = typename JITAssembler::TrustedImm32;
- using TrustedImm64 = typename JITAssembler::TrustedImm64;
- using Label = typename JITAssembler::Label;
- using Jump = typename JITAssembler::Jump;
- using StringToIndex = typename JITAssembler::StringToIndex;
- using Reference = typename JITAssembler::Reference;
- using RelationalCondition = typename JITAssembler::RelationalCondition;
- using BranchTruncateType = typename JITAssembler::BranchTruncateType;
- using RuntimeCall = typename JITAssembler::RuntimeCall;
-
- using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
-
- Address addressForArgument(int index) const
- {
- // FramePointerRegister points to its old value on the stack, and above
- // it we have the return address, hence the need to step over two
- // values before reaching the first argument.
- return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * JITTargetPlatform::RegisterSize);
- }
-
- Pointer baseAddressForCallArguments()
- {
- return _as->stackLayout().argumentAddressForCall(0);
- }
-
- Pointer baseAddressForCallData()
- {
- return _as->stackLayout().callDataAddress();
- }
-
- void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) override;
- void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr*result) override;
- void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override;
-
- void visitJump(IR::Jump *) override;
- void visitCJump(IR::CJump *) override;
- void visitRet(IR::Ret *) override;
-
- bool visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
- IR::BasicBlock *iftrue, IR::BasicBlock *iffalse);
- bool visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
- IR::BasicBlock *iftrue, IR::BasicBlock *iffalse);
- void visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- bool visitCJumpStrictNull(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- bool visitCJumpStrictUndefined(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- bool visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- bool visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
- IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
- void visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
-
-private:
- void convertTypeSlowPath(IR::Expr *source, IR::Expr *target);
- void convertTypeToDouble(IR::Expr *source, IR::Expr *target);
- void convertTypeToBool(IR::Expr *source, IR::Expr *target);
- void convertTypeToSInt32(IR::Expr *source, IR::Expr *target);
- void convertTypeToUInt32(IR::Expr *source, IR::Expr *target);
-
- void convertIntToDouble(IR::Expr *source, IR::Expr *target)
- {
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- if (IR::Temp *sourceTemp = source->asTemp()) {
- if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertInt32ToDouble((RegisterID) sourceTemp->index,
- (FPRegisterID) targetTemp->index);
- } else {
- _as->convertInt32ToDouble(_as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, sourceTemp),
- (FPRegisterID) targetTemp->index);
- }
- } else {
- _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
- (FPRegisterID) targetTemp->index);
- }
-
- return;
- }
- }
-
- _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
- JITTargetPlatform::FPGpr0);
- _as->storeDouble(JITTargetPlatform::FPGpr0, target);
- }
-
- void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
- {
- RegisterID tmpReg = JITTargetPlatform::ScratchRegister;
- RegisterID reg = _as->toInt32Register(source, tmpReg);
-
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(reg, (FPRegisterID) targetTemp->index, tmpReg);
- return;
- }
- }
-
- _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
- JITTargetPlatform::FPGpr0, tmpReg);
- _as->storeDouble(JITTargetPlatform::FPGpr0, target);
- }
-
- void convertIntToBool(IR::Expr *source, IR::Expr *target)
- {
- RegisterID reg = JITTargetPlatform::ScratchRegister;
-
- if (IR::Temp *targetTemp = target->asTemp())
- if (targetTemp->kind == IR::Temp::PhysicalRegister)
- reg = (RegisterID) targetTemp->index;
- _as->move(_as->toInt32Register(source, reg), reg);
- _as->compare32(RelationalCondition::NotEqual, reg, TrustedImm32(0), reg);
- _as->storeBool(reg, target);
- }
-
- int prepareVariableArguments(IR::ExprList* args);
- int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
-
- void calculateRegistersToSave(const RegisterInformation &used);
-
- template <typename Retval, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
- {
- // Note: using the return value register is intentional: for ABIs where the first parameter
- // goes into the same register as the return value (currently only ARM), the prepareCall
- // will combine loading the looupAddr into the register and calculating the indirect call
- // address.
- Pointer lookupAddr(JITTargetPlatform::ReturnValueRegister, index * sizeof(QV4::Lookup));
-
- _as->generateFunctionCallImp(true, retval, "lookup getter/setter",
- typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
- arg1, arg2, arg3, arg4);
- }
-
- template <typename Retval, typename Arg1, typename Arg2>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
- {
- generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
- }
-
- template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
- {
- generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, arg3, typename JITAssembler::VoidType());
- }
-
- IR::BasicBlock *_block;
- BitVector _removableJumps;
- JITAssembler* _as;
-
- QScopedPointer<CompilationUnit> compilationUnit;
- QQmlEnginePrivate *qmlEngine;
- RegisterInformation regularRegistersToSave;
- RegisterInformation fpRegistersToSave;
-};
-
-template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
-class Q_QML_EXPORT ISelFactory: public EvalISelFactory
-{
-public:
- ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
- virtual ~ISelFactory() {}
- EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
- { return new InstructionSelection<JITAssembler>(qmlEngine, execAllocator, module, jsGenerator, this); }
- bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
- { return true; }
- QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
-};
-
-} // end of namespace JIT
-} // end of namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // ENABLE(ASSEMBLER)
-
-#endif // QV4ISEL_MASM_P_H
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
deleted file mode 100644
index d418b050c4..0000000000
--- a/src/qml/jit/qv4regalloc.cpp
+++ /dev/null
@@ -1,1971 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the V4VM module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 <QtCore/QBuffer>
-#include <QtCore/QDebug>
-#include "qv4regalloc_p.h"
-#include "qv4alloca_p.h"
-#include <private/qv4value_p.h>
-
-#include <algorithm>
-#if defined(Q_CC_MINGW)
-# include <malloc.h>
-#endif
-
-namespace {
-enum { DebugRegAlloc = 0 };
-
-struct Use {
- enum RegisterFlag { MustHaveRegister = 0, CouldHaveRegister = 1 };
- unsigned flag : 1;
- unsigned pos : 31;
-
- Use(): flag(MustHaveRegister), pos(0) {}
- Use(int position, RegisterFlag flag): flag(flag), pos(position)
- { Q_ASSERT(position >= 0); }
-
- bool mustHaveRegister() const { return flag == MustHaveRegister; }
-};
-}
-
-QT_BEGIN_NAMESPACE
-
-Q_DECLARE_TYPEINFO(Use, Q_MOVABLE_TYPE);
-
-using namespace QV4::IR;
-
-namespace QV4 {
-namespace JIT {
-
-namespace {
-class IRPrinterWithPositions: public IRPrinter
-{
- LifeTimeIntervals::Ptr intervals;
- const int positionSize;
-
-public:
- IRPrinterWithPositions(QTextStream *out, const LifeTimeIntervals::Ptr &intervals)
- : IRPrinter(out)
- , intervals(intervals)
- , positionSize(QString::number(intervals->lastPosition()).size())
- {}
-
-protected:
- void addStmtNr(Stmt *s) Q_DECL_OVERRIDE Q_DECL_FINAL
- {
- addJustifiedNr(intervals->positionForStatement(s));
- }
-};
-
-class IRPrinterWithRegisters: public IRPrinterWithPositions
-{
- const RegisterInformation &_registerInformation;
- QHash<int, const RegisterInfo *> _infoForRegularRegister;
- QHash<int, const RegisterInfo *> _infoForFPRegister;
-
-public:
- IRPrinterWithRegisters(QTextStream *out, const LifeTimeIntervals::Ptr &intervals,
- const RegisterInformation &registerInformation)
- : IRPrinterWithPositions(out, intervals)
- , _registerInformation(registerInformation)
- {
- for (int i = 0, ei = _registerInformation.size(); i != ei; ++i)
- if (_registerInformation.at(i).isRegularRegister())
- _infoForRegularRegister.insert(_registerInformation.at(i).reg<int>(),
- &_registerInformation.at(i));
- else
- _infoForFPRegister.insert(_registerInformation.at(i).reg<int>(),
- &_registerInformation.at(i));
- }
-
-protected:
- void visitTemp(Temp *e) Q_DECL_OVERRIDE Q_DECL_FINAL
- {
- switch (e->kind) {
- case Temp::PhysicalRegister: {
- const RegisterInfo *ri = e->type == DoubleType ? _infoForFPRegister.value(e->index, 0)
- : _infoForRegularRegister.value(e->index, 0);
- if (ri) {
- *out << ri->prettyName();
- break;
- }
- Q_FALLTHROUGH();
- }
- default:
- IRPrinterWithPositions::visitTemp(e);
- }
- }
-};
-}
-
-class RegAllocInfo: public IRDecoder
-{
-public:
- typedef QVarLengthArray<Temp, 4> Hints;
-
-private:
- struct Def {
- unsigned valid : 1;
- unsigned canHaveReg : 1;
- unsigned isPhiTarget : 1;
-
- Def(): valid(0), canHaveReg(0), isPhiTarget(0) {}
- Def(bool canHaveReg, bool isPhiTarget)
- : valid(1), canHaveReg(canHaveReg), isPhiTarget(isPhiTarget)
- {
- }
-
- bool isValid() const { return valid != 0; }
- };
-
- IR::LifeTimeIntervals::Ptr _lifeTimeIntervals;
- BasicBlock *_currentBB;
- Stmt *_currentStmt;
- std::vector<Def> _defs;
- std::vector<std::vector<Use> > _uses;
- std::vector<int> _calls;
- std::vector<Hints> _hints;
-
- int usePosition(Stmt *s) const
- {
- int usePos = _lifeTimeIntervals->positionForStatement(s);
- if (usePos == Stmt::InvalidId) // phi-node operand, so:
- usePos = _lifeTimeIntervals->startPosition(_currentBB);
- return usePos;
- }
-
-public:
- RegAllocInfo(): _currentBB(0), _currentStmt(0) {}
-
- void collect(IR::Function *function, const IR::LifeTimeIntervals::Ptr &lifeTimeIntervals)
- {
- _lifeTimeIntervals = lifeTimeIntervals;
- _defs.resize(function->tempCount);
- _uses.resize(function->tempCount);
- _calls.reserve(function->statementCount() / 3);
- _hints.resize(function->tempCount);
-
- for (BasicBlock *bb : function->basicBlocks()) {
- _currentBB = bb;
- for (Stmt *s : bb->statements()) {
- _currentStmt = s;
- visit(s);
- }
- }
- }
-
- const std::vector<Use> &uses(const Temp &t) const
- {
- return _uses.at(t.index);
- }
-
- bool canHaveRegister(const Temp &t) const {
- Q_ASSERT(_defs[t.index].isValid());
- return _defs[t.index].canHaveReg;
- }
- bool isPhiTarget(const Temp &t) const {
- Q_ASSERT(_defs[t.index].isValid());
- return _defs[t.index].isPhiTarget;
- }
-
- const std::vector<int> &calls() const { return _calls; }
- const Hints &hints(const Temp &t) const { return _hints[t.index]; }
- void addHint(const Temp &t, int physicalRegister)
- { addHint(t, Temp::PhysicalRegister, physicalRegister); }
-
- void addHint(const Temp &t, Temp::Kind kind, int hintedIndex)
- {
- Hints &hints = _hints[t.index];
- for (Hints::iterator i = hints.begin(), ei = hints.end(); i != ei; ++i)
- if (i->index == hintedIndex)
- return;
-
- Temp hint;
- hint.init(kind, hintedIndex);
- hints.append(hint);
- }
-
- void dump() const
- {
- if (!DebugRegAlloc)
- return;
-
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithPositions printer(&qout, _lifeTimeIntervals);
-
- qout << "RegAllocInfo:" << endl << "Defs/uses:" << endl;
- for (unsigned t = 0; t < _defs.size(); ++t) {
- const std::vector<Use> &uses = _uses[t];
- if (uses.empty())
- continue;
- qout << "%" << t <<": "
- << " ("
- << (_defs[t].canHaveReg ? "can" : "can NOT")
- << " have a register, and "
- << (_defs[t].isPhiTarget ? "is" : "is NOT")
- << " defined by a phi node), uses at: ";
- for (unsigned i = 0; i < uses.size(); ++i) {
- if (i > 0) qout << ", ";
- qout << uses[i].pos;
- if (uses[i].mustHaveRegister()) qout << "(R)"; else qout << "(S)";
- }
- qout << endl;
- }
-
- qout << "Calls at: ";
- for (unsigned i = 0; i < _calls.size(); ++i) {
- if (i > 0) qout << ", ";
- qout << _calls[i];
- }
- qout << endl;
-
- qout << "Hints:" << endl;
- for (unsigned t = 0; t < _hints.size(); ++t) {
- if (_uses[t].empty())
- continue;
- qout << "\t%" << t << ": ";
- const Hints &hints = _hints[t];
- for (int i = 0; i < hints.size(); ++i) {
- if (i > 0) qout << ", ";
- printer.print(hints[i]);
- }
- qout << endl;
- }
- qDebug("%s", buf.data().constData());
- }
-
-protected: // IRDecoder
- void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Expr *) override {}
- void callBuiltinTypeofQmlContextProperty(IR::Expr *, IR::Member::MemberKind, int, IR::Expr *) override {}
- void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Expr *) override {}
- void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Expr *) override {}
- void callBuiltinTypeofName(const QString &, IR::Expr *) override {}
- void callBuiltinTypeofValue(IR::Expr *, IR::Expr *) override {}
- void callBuiltinDeleteMember(IR::Expr *, const QString &, IR::Expr *) override {}
- void callBuiltinDeleteSubscript(IR::Expr *, IR::Expr *, IR::Expr *) override {}
- void callBuiltinDeleteName(const QString &, IR::Expr *) override {}
- void callBuiltinDeleteValue(IR::Expr *) override {}
- void callBuiltinThrow(IR::Expr *) override {}
- void callBuiltinReThrow() override {}
- void callBuiltinUnwindException(IR::Expr *) override {}
- void callBuiltinPushCatchScope(const QString &) override {};
- void callBuiltinForeachIteratorObject(IR::Expr *, IR::Expr *) override {}
- virtual void callBuiltinForeachNextProperty(IR::Temp *, IR::Temp *) {}
- void callBuiltinForeachNextPropertyname(IR::Expr *, IR::Expr *) override {}
- void callBuiltinPushWithScope(IR::Expr *) override {}
- void callBuiltinPopScope() override {}
- void callBuiltinDeclareVar(bool , const QString &) override {}
- void callBuiltinDefineArray(IR::Expr *, IR::ExprList *) override {}
- void callBuiltinDefineObjectLiteral(IR::Expr *, int, IR::ExprList *, IR::ExprList *, bool) override {}
- void callBuiltinSetupArgumentObject(IR::Expr *) override {}
- void callBuiltinConvertThisToObject() override {}
-
- void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override
- {
- addDef(result);
- if (IR::Temp *tempValue = value->asTemp())
- addUses(tempValue, Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int propertyIndex,
- IR::ExprList *args, IR::Expr *result) override
- {
- Q_UNUSED(propertyIndex)
-
- addDef(result);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
- IR::Expr *result) override
- {
- Q_UNUSED(name)
-
- addDef(result);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
- IR::Expr *result) override
- {
- addDef(result);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addUses(index->asTemp(), Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void convertType(IR::Expr *source, IR::Expr *target) override
- {
- addDef(target);
-
- bool needsCall = true;
- Use::RegisterFlag sourceReg = Use::CouldHaveRegister;
-
- switch (target->type) {
- case DoubleType:
- switch (source->type) {
- case UInt32Type:
- case SInt32Type:
- case NullType:
- case UndefinedType:
- case BoolType:
- needsCall = false;
- break;
- default:
- break;
- }
- break;
- case BoolType:
- switch (source->type) {
- case UInt32Type:
- sourceReg = Use::MustHaveRegister;
- needsCall = false;
- break;
- case DoubleType:
- case UndefinedType:
- case NullType:
- case SInt32Type:
- needsCall = false;
- break;
- default:
- break;
- }
- break;
- case SInt32Type:
- switch (source->type) {
- case UInt32Type:
- case NullType:
- case UndefinedType:
- case BoolType:
- needsCall = false;
- default:
- break;
- }
- break;
- case UInt32Type:
- switch (source->type) {
- case SInt32Type:
- case NullType:
- case UndefinedType:
- case BoolType:
- needsCall = false;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- Temp *sourceTemp = source->asTemp();
- if (sourceTemp)
- addUses(sourceTemp, sourceReg);
-
- if (needsCall)
- addCall();
- else if (target->asTemp())
- addHint(target->asTemp(), sourceTemp);
- }
-
- void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Expr *result) override
- {
- addDef(result);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void constructProperty(IR::Expr *base, const QString &, IR::ExprList *args, IR::Expr *result) override
- {
- addDef(result);
- addUses(base, Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) override
- {
- addDef(result);
- addUses(value, Use::CouldHaveRegister);
- addUses(args, Use::CouldHaveRegister);
- addCall();
- }
-
- void loadThisObject(IR::Expr *temp) override
- {
- addDef(temp);
- }
-
- void loadQmlContext(IR::Expr *temp) override
- {
- addDef(temp);
- addCall();
- }
-
- void loadQmlImportedScripts(IR::Expr *temp) override
- {
- addDef(temp);
- addCall();
- }
-
- void loadQmlSingleton(const QString &/*name*/, Expr *temp) override
- {
- Q_UNUSED(temp);
-
- addDef(temp);
- addCall();
- }
-
- void loadConst(IR::Const *sourceConst, Expr *targetTemp) override
- {
- Q_UNUSED(sourceConst);
-
- addDef(targetTemp);
- }
-
- void loadString(const QString &str, Expr *targetTemp) override
- {
- Q_UNUSED(str);
-
- addDef(targetTemp);
- }
-
- void loadRegexp(IR::RegExp *sourceRegexp, Expr *targetTemp) override
- {
- Q_UNUSED(sourceRegexp);
-
- addDef(targetTemp);
- addCall();
- }
-
- void getActivationProperty(const IR::Name *, Expr *temp) override
- {
- addDef(temp);
- addCall();
- }
-
- void setActivationProperty(IR::Expr *source, const QString &) override
- {
- addUses(source->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void initClosure(IR::Closure *closure, Expr *target) override
- {
- Q_UNUSED(closure);
-
- addDef(target);
- addCall();
- }
-
- void getProperty(IR::Expr *base, const QString &, Expr *target) override
- {
- addDef(target);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &) override
- {
- addUses(source->asTemp(), Use::CouldHaveRegister);
- addUses(targetBase->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase,
- IR::Member::MemberKind /*kind*/, int /*propertyIndex*/) override
- {
- addUses(source->asTemp(), Use::CouldHaveRegister);
- addUses(targetBase->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int /*propertyIndex*/) override
- {
- addUses(source->asTemp(), Use::CouldHaveRegister);
- addUses(targetBase->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int /*index*/,
- bool /*captureRequired*/, IR::Expr *target) override
- {
- addDef(target);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/,
- bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target) override
- {
- addDef(target);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void getElement(IR::Expr *base, IR::Expr *index, Expr *target) override
- {
- addDef(target);
- addUses(base->asTemp(), Use::CouldHaveRegister);
- addUses(index->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) override
- {
- addUses(source->asTemp(), Use::CouldHaveRegister);
- addUses(targetBase->asTemp(), Use::CouldHaveRegister);
- addUses(targetIndex->asTemp(), Use::CouldHaveRegister);
- addCall();
- }
-
- void copyValue(Expr *source, Expr *target) override
- {
- addDef(target);
- Temp *sourceTemp = source->asTemp();
- if (!sourceTemp)
- return;
- addUses(sourceTemp, Use::CouldHaveRegister);
- Temp *targetTemp = target->asTemp();
- if (targetTemp)
- addHint(targetTemp, sourceTemp);
- }
-
- void swapValues(Expr *, Expr *) override
- {
- // Inserted by the register allocator, so it cannot occur here.
- Q_UNREACHABLE();
- }
-
- void unop(AluOp oper, Expr *source, Expr *target) override
- {
- addDef(target);
-
- bool needsCall = true;
- if (oper == OpNot && source->type == IR::BoolType && target->type == IR::BoolType)
- needsCall = false;
-
-#if 0 // TODO: change masm to generate code
- switch (oper) {
- case OpIfTrue:
- case OpNot:
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- needsCall = sourceTemp->type & ~NumberType && sourceTemp->type != BoolType;
- break;
-
- case OpIncrement:
- case OpDecrement:
- default:
- Q_UNREACHABLE();
- }
-#endif
-
- IR::Temp *sourceTemp = source->asTemp();
- if (needsCall) {
- if (sourceTemp)
- addUses(sourceTemp, Use::CouldHaveRegister);
- addCall();
- } else {
- if (sourceTemp)
- addUses(sourceTemp, Use::MustHaveRegister);
- }
- }
-
- void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Expr *target) override
- {
- bool needsCall = true;
-
- if (oper == OpStrictEqual || oper == OpStrictNotEqual) {
- bool noCall = leftSource->type == NullType || rightSource->type == NullType
- || leftSource->type == UndefinedType || rightSource->type == UndefinedType
- || leftSource->type == BoolType || rightSource->type == BoolType;
- needsCall = !noCall;
- } else if (leftSource->type == DoubleType && rightSource->type == DoubleType) {
- if (oper == OpMul || oper == OpAdd || oper == OpDiv || oper == OpSub
- || (oper >= OpGt && oper <= OpStrictNotEqual)) {
- needsCall = false;
- }
- } else if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
- needsCall = false;
- } else if (oper == OpAdd || oper == OpMul || oper == OpSub
- || (oper >= OpGt && oper <= OpStrictNotEqual)) {
- if (leftSource->type == SInt32Type && rightSource->type == SInt32Type)
- needsCall = false;
- }
-
- addDef(target);
-
- if (needsCall) {
- addUses(leftSource->asTemp(), Use::CouldHaveRegister);
- addUses(rightSource->asTemp(), Use::CouldHaveRegister);
- addCall();
- } else {
- addUses(leftSource->asTemp(), Use::MustHaveRegister);
- addHint(target, leftSource->asTemp());
- addHint(target, rightSource->asTemp());
-
-#if CPU(X86) || CPU(X86_64)
- switch (oper) {
- // The rhs operand can be a memory address
- case OpAdd:
- case OpSub:
- case OpMul:
- case OpDiv:
-#if CPU(X86_64)
- if (leftSource->type == DoubleType || rightSource->type == DoubleType) {
- // well, on 64bit the doubles are mangled, so they must first be loaded in a register and demangled, so...:
- addUses(rightSource->asTemp(), Use::MustHaveRegister);
- break;
- }
- Q_FALLTHROUGH();
-#endif
- case OpBitAnd:
- case OpBitOr:
- case OpBitXor:
- addUses(rightSource->asTemp(), Use::CouldHaveRegister);
- break;
-
- default:
- addUses(rightSource->asTemp(), Use::MustHaveRegister);
- break;
- }
-#else
- addUses(rightSource->asTemp(), Use::MustHaveRegister);
-#endif
- }
- }
-
- void visitJump(IR::Jump *) override {}
- void visitCJump(IR::CJump *s) override
- {
- if (Temp *t = s->cond->asTemp()) {
-#if 0 // TODO: change masm to generate code
- addUses(t, Use::MustHaveRegister);
-#else
- addUses(t, Use::CouldHaveRegister);
- addCall();
-#endif
- } else if (Binop *b = s->cond->asBinop()) {
- binop(b->op, b->left, b->right, 0);
- } else if (s->cond->asConst()) {
- // TODO: SSA optimization for constant condition evaluation should remove this.
- // See also visitCJump() in masm.
- addCall();
- } else {
- Q_UNREACHABLE();
- }
- }
-
- void visitRet(IR::Ret *s) override
- { addUses(s->expr->asTemp(), Use::CouldHaveRegister); }
-
- void visitPhi(IR::Phi *s) override
- {
- addDef(s->targetTemp, true);
- for (int i = 0, ei = s->incoming.size(); i < ei; ++i) {
- Expr *e = s->incoming.at(i);
- if (Temp *t = e->asTemp()) {
- // The actual use of an incoming value in a phi node is right before the terminator
- // of the other side of the incoming edge.
- const int usePos = _lifeTimeIntervals->positionForStatement(_currentBB->in.at(i)->terminator()) - 1;
- addUses(t, Use::CouldHaveRegister, usePos);
- addHint(s->targetTemp, t);
- addHint(t, s->targetTemp);
- }
- }
- }
-
-protected:
- void callBuiltin(IR::Call *c, IR::Expr *result) override
- {
- addDef(result);
- addUses(c->base, Use::CouldHaveRegister);
- addUses(c->args, Use::CouldHaveRegister);
- addCall();
- }
-
-private:
- void addDef(Expr *e, bool isPhiTarget = false)
- {
- if (!e)
- return;
- Temp *t = e->asTemp();
- if (!t)
- return;
- if (!t || t->kind != Temp::VirtualRegister)
- return;
- Q_ASSERT(!_defs[t->index].isValid());
- bool canHaveReg = true;
- switch (t->type) {
- case QObjectType:
- case VarType:
- case StringType:
- case UndefinedType:
- case NullType:
- canHaveReg = false;
- break;
- default:
- break;
- }
-
- _defs[t->index] = Def(canHaveReg, isPhiTarget);
- }
-
- void addUses(Expr *e, Use::RegisterFlag flag)
- {
- const int usePos = usePosition(_currentStmt);
- addUses(e, flag, usePos);
- }
-
- void addUses(Expr *e, Use::RegisterFlag flag, int usePos)
- {
- Q_ASSERT(usePos > 0);
- if (!e)
- return;
- Temp *t = e->asTemp();
- if (!t)
- return;
- if (t && t->kind == Temp::VirtualRegister)
- _uses[t->index].push_back(Use(usePos, flag));
- }
-
- void addUses(ExprList *l, Use::RegisterFlag flag)
- {
- for (ExprList *it = l; it; it = it->next)
- addUses(it->expr, flag);
- }
-
- void addCall()
- {
- _calls.push_back(usePosition(_currentStmt));
- }
-
- void addHint(Expr *hinted, Temp *hint1, Temp *hint2 = 0)
- {
- if (hinted)
- if (Temp *hintedTemp = hinted->asTemp())
- addHint(hintedTemp, hint1, hint2);
- }
-
- void addHint(Temp *hinted, Temp *hint1, Temp *hint2 = 0)
- {
- if (!hinted || hinted->kind != Temp::VirtualRegister)
- return;
- if (hint1 && hint1->kind == Temp::VirtualRegister && hinted->type == hint1->type)
- addHint(*hinted, Temp::VirtualRegister, hint1->index);
- if (hint2 && hint2->kind == Temp::VirtualRegister && hinted->type == hint2->type)
- addHint(*hinted, Temp::VirtualRegister, hint2->index);
- }
-};
-
-} // JIT namespace
-} // QV4 namespace
-QT_END_NAMESPACE
-
-QT_USE_NAMESPACE
-
-using namespace QT_PREPEND_NAMESPACE(QV4::JIT);
-using namespace QT_PREPEND_NAMESPACE(QV4::IR);
-using namespace QT_PREPEND_NAMESPACE(QV4);
-
-namespace {
-class ResolutionPhase
-{
- Q_DISABLE_COPY(ResolutionPhase)
-
- LifeTimeIntervals::Ptr _intervals;
- QVector<LifeTimeInterval *> _unprocessedReverseOrder;
- IR::Function *_function;
- const std::vector<int> &_assignedSpillSlots;
- std::vector<const LifeTimeInterval *> _liveIntervals;
- const QVector<const RegisterInfo *> &_intRegs;
- const QVector<const RegisterInfo *> &_fpRegs;
-
- Stmt *_currentStmt;
- std::vector<Move *> _loads;
- std::vector<Move *> _stores;
-
- std::vector<std::vector<const LifeTimeInterval *> > _liveAtStart;
- std::vector<std::vector<const LifeTimeInterval *> > _liveAtEnd;
-
-public:
- ResolutionPhase(QVector<LifeTimeInterval *> &&unprocessedReversedOrder,
- const LifeTimeIntervals::Ptr &intervals,
- IR::Function *function,
- const std::vector<int> &assignedSpillSlots,
- const QVector<const RegisterInfo *> &intRegs,
- const QVector<const RegisterInfo *> &fpRegs)
- : _intervals(intervals)
- , _unprocessedReverseOrder(unprocessedReversedOrder)
- , _function(function)
- , _assignedSpillSlots(assignedSpillSlots)
- , _intRegs(intRegs)
- , _fpRegs(fpRegs)
- , _currentStmt(0)
- {
- _liveAtStart.resize(function->basicBlockCount());
- _liveAtEnd.resize(function->basicBlockCount());
- }
-
- void run() {
- renumber();
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithPositions(&qout, _intervals).print(_function);
- qDebug("%s", buf.data().constData());
- }
- resolve();
- }
-
-private:
- int defPosition(Stmt *s) const
- {
- return usePosition(s) + 1;
- }
-
- int usePosition(Stmt *s) const
- {
- return _intervals->positionForStatement(s);
- }
-
- void renumber()
- {
- QVector<Stmt *> newStatements;
-
- for (BasicBlock *bb : _function->basicBlocks()) {
- _currentStmt = 0;
-
- QVector<Stmt *> statements = bb->statements();
- newStatements.reserve(bb->statements().size() + 7);
- newStatements.erase(newStatements.begin(), newStatements.end());
-
- cleanOldIntervals(_intervals->startPosition(bb));
- addNewIntervals(_intervals->startPosition(bb));
- _liveAtStart[bb->index()] = _liveIntervals;
-
- for (int i = 0, ei = statements.size(); i != ei; ++i) {
- _currentStmt = statements.at(i);
- _loads.clear();
- _stores.clear();
- if (_currentStmt->asTerminator())
- addNewIntervals(usePosition(_currentStmt));
- else
- addNewIntervals(defPosition(_currentStmt));
- visit(_currentStmt);
- for (Move *load : _loads)
- newStatements.append(load);
- if (_currentStmt->asPhi())
- newStatements.prepend(_currentStmt);
- else
- newStatements.append(_currentStmt);
- for (Move *store : _stores)
- newStatements.append(store);
- }
-
- cleanOldIntervals(_intervals->endPosition(bb));
- _liveAtEnd[bb->index()] = _liveIntervals;
-
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream os(&buf);
- os << "Intervals live at the start of L" << bb->index() << ":" << endl;
- if (_liveAtStart[bb->index()].empty())
- os << "\t(none)" << endl;
- for (const LifeTimeInterval *i : _liveAtStart.at(bb->index())) {
- os << "\t";
- i->dump(os);
- os << endl;
- }
- os << "Intervals live at the end of L" << bb->index() << ":" << endl;
- if (_liveAtEnd[bb->index()].empty())
- os << "\t(none)" << endl;
- for (const LifeTimeInterval *i : _liveAtEnd.at(bb->index())) {
- os << "\t";
- i->dump(os);
- os << endl;
- }
- qDebug("%s", buf.data().constData());
- }
-
- bb->setStatements(newStatements);
- }
-
- }
-
- const LifeTimeInterval *findLiveInterval(Temp *t) const
- {
- for (const LifeTimeInterval *lti : _liveIntervals) {
- if (lti->temp() == *t)
- return lti;
- }
-
- return nullptr;
- }
-
- void maybeGenerateSpill(Temp *t)
- {
- const LifeTimeInterval *i = findLiveInterval(t);
- if (i->reg() == LifeTimeInterval::InvalidRegister)
- return;
-
- const RegisterInfo *pReg = platformRegister(*i);
- Q_ASSERT(pReg);
- int spillSlot = _assignedSpillSlots[i->temp().index];
- if (spillSlot != RegisterAllocator::InvalidSpillSlot)
- _stores.push_back(generateSpill(spillSlot, i->temp().type, pReg->reg<int>()));
- }
-
- void addNewIntervals(int position)
- {
- if (position == Stmt::InvalidId)
- return;
-
- while (!_unprocessedReverseOrder.isEmpty()) {
- const LifeTimeInterval *i = _unprocessedReverseOrder.constLast();
- if (i->start() > position)
- break;
-
- Q_ASSERT(!i->isFixedInterval());
- auto it = _liveIntervals.begin();
- for (; it != _liveIntervals.end(); ++it) {
- if ((*it)->temp() == i->temp()) {
- *it = i;
- break;
- }
- }
- if (it == _liveIntervals.end())
- _liveIntervals.push_back(i);
-// qDebug() << "-- Activating interval for temp" << i->temp().index;
-
- _unprocessedReverseOrder.removeLast();
- }
- }
-
- void cleanOldIntervals(int position)
- {
- for (size_t it = 0; it != _liveIntervals.size(); ) {
- const LifeTimeInterval *lti = _liveIntervals.at(it);
- if (lti->end() < position || lti->isFixedInterval())
- _liveIntervals.erase(_liveIntervals.begin() + it);
- else
- ++it;
- }
- }
-
- void resolve()
- {
- for (BasicBlock *bb : _function->basicBlocks()) {
- for (BasicBlock *bbOut : bb->out)
- resolveEdge(bb, bbOut);
- }
- }
-
- Phi *findDefPhi(const Temp &t, BasicBlock *bb) const
- {
- for (Stmt *s : bb->statements()) {
- Phi *phi = s->asPhi();
- if (!phi)
- return 0;
-
- if (*phi->targetTemp == t)
- return phi;
- }
-
- Q_UNREACHABLE();
- }
-
- void resolveEdge(BasicBlock *predecessor, BasicBlock *successor)
- {
- if (DebugRegAlloc) {
- qDebug() << "Resolving edge" << predecessor->index() << "->" << successor->index();
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithPositions printer(&qout, _intervals);
- printer.print(predecessor);
- printer.print(successor);
- qDebug("%s", buf.data().constData());
- }
-
- MoveMapping mapping;
-
- const int predecessorEnd = _intervals->endPosition(predecessor);
- Q_ASSERT(predecessorEnd > 0);
-
- int successorStart = _intervals->startPosition(successor);
- Q_ASSERT(successorStart > 0);
-
- for (const LifeTimeInterval *it : _liveAtStart.at(successor->index())) {
- bool isPhiTarget = false;
- Expr *moveFrom = 0;
-
- if (it->start() == successorStart) {
- if (Phi *phi = findDefPhi(it->temp(), successor)) {
- isPhiTarget = true;
- Expr *opd = phi->incoming[successor->in.indexOf(predecessor)];
- if (opd->asConst()) {
- moveFrom = opd;
- } else {
- Temp *t = opd->asTemp();
- Q_ASSERT(t);
-
- for (const LifeTimeInterval *it2 : _liveAtEnd.at(predecessor->index())) {
- if (it2->temp() == *t
- && it2->reg() != LifeTimeInterval::InvalidRegister
- && it2->covers(predecessorEnd)) {
- moveFrom = createPhysicalRegister(it2, t->type);
- break;
- }
- }
- if (!moveFrom)
- moveFrom = createTemp(Temp::StackSlot,
- _assignedSpillSlots[t->index],
- t->type);
- }
- }
- } else {
- for (const LifeTimeInterval *predIt : _liveAtEnd.at(predecessor->index())) {
- if (predIt->temp() == it->temp()) {
- if (predIt->reg() != LifeTimeInterval::InvalidRegister
- && predIt->covers(predecessorEnd)) {
- moveFrom = createPhysicalRegister(predIt, predIt->temp().type);
- } else {
- int spillSlot = _assignedSpillSlots[predIt->temp().index];
- if (spillSlot != -1)
- moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type);
- }
- break;
- }
- }
- }
- if (!moveFrom) {
-#if !defined(QT_NO_DEBUG) && 0
- bool lifeTimeHole = false;
- if (it->ranges().first().start <= successorStart && it->ranges().last().end >= successorStart)
- lifeTimeHole = !it->covers(successorStart);
-
- Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
- if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
- const int successorEnd = successor->terminator()->id();
- const int idx = successor->in.indexOf(predecessor);
- for (const Use &use : _info->uses(it->temp)) {
- if (use.pos == static_cast<unsigned>(successorStart)) {
- // only check the current edge, not all other possible ones. This is
- // important for phi nodes: they have uses that are only valid when
- // coming in over a specific edge.
- for (Stmt *s : successor->statements()) {
- if (Phi *phi = s->asPhi()) {
- Q_ASSERT(it->temp().index != phi->targetTemp->index);
- Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0
- || it->temp().index != phi->d->incoming[idx]->asTemp()->index);
- } else {
- // TODO: check that the first non-phi statement does not use
- // the temp.
- break;
- }
- }
- } else {
- Q_ASSERT(use.pos < static_cast<unsigned>(successorStart) ||
- use.pos > static_cast<unsigned>(successorEnd));
- }
- }
- }
-#endif
-
- continue;
- }
-
- Temp *moveTo;
- if (it->reg() == LifeTimeInterval::InvalidRegister || !it->covers(successorStart)) {
- if (!isPhiTarget) // if it->temp() is a phi target, skip it.
- continue;
- const int spillSlot = _assignedSpillSlots[it->temp().index];
- if (spillSlot == RegisterAllocator::InvalidSpillSlot)
- continue; // it has a life-time hole here.
- moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type);
- } else {
- moveTo = createPhysicalRegister(it, it->temp().type);
- }
-
- // add move to mapping
- mapping.add(moveFrom, moveTo);
- }
-
- if (DebugRegAlloc)
- mapping.dump();
- mapping.order();
- if (DebugRegAlloc)
- mapping.dump();
-
- bool insertIntoPredecessor = successor->in.size() > 1;
- mapping.insertMoves(insertIntoPredecessor ? predecessor : successor, _function,
- insertIntoPredecessor);
-
- if (DebugRegAlloc) {
- qDebug() << ".. done, result:";
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithPositions printer(&qout, _intervals);
- printer.print(predecessor);
- printer.print(successor);
- qDebug("%s", buf.data().constData());
- }
- }
-
- Temp *createTemp(Temp::Kind kind, int index, Type type) const
- {
- Q_ASSERT(index >= 0);
- Temp *t = _function->New<Temp>();
- t->init(kind, index);
- t->type = type;
- return t;
- }
-
- Temp *createPhysicalRegister(const LifeTimeInterval *i, Type type) const
- {
- const RegisterInfo *ri = platformRegister(*i);
- Q_ASSERT(ri);
- return createTemp(Temp::PhysicalRegister, ri->reg<int>(), type);
- }
-
- const RegisterInfo *platformRegister(const LifeTimeInterval &i) const
- {
- if (i.isFP())
- return _fpRegs.value(i.reg(), 0);
- else
- return _intRegs.value(i.reg(), 0);
- }
-
- Move *generateSpill(int spillSlot, Type type, int pReg) const
- {
- Q_ASSERT(spillSlot >= 0);
-
- Move *store = _function->NewStmt<Move>();
- store->init(createTemp(Temp::StackSlot, spillSlot, type),
- createTemp(Temp::PhysicalRegister, pReg, type));
- return store;
- }
-
- Move *generateUnspill(const Temp &t, int pReg) const
- {
- Q_ASSERT(pReg >= 0);
- int spillSlot = _assignedSpillSlots[t.index];
- Q_ASSERT(spillSlot != -1);
- Move *load = _function->NewStmt<Move>();
- load->init(createTemp(Temp::PhysicalRegister, pReg, t.type),
- createTemp(Temp::StackSlot, spillSlot, t.type));
- return load;
- }
-
-private:
- void visit(Expr *e)
- {
- switch (e->exprKind) {
- case Expr::TempExpr:
- visitTemp(e->asTemp());
- break;
- default:
- EXPR_VISIT_ALL_KINDS(e);
- break;
- }
- }
-
- void visitTemp(Temp *t)
- {
- if (t->kind != Temp::VirtualRegister)
- return;
-
- const LifeTimeInterval *i = findLiveInterval(t);
- Q_ASSERT(i->isValid());
-
- if (_currentStmt != 0 && i->start() == usePosition(_currentStmt)) {
- Q_ASSERT(i->isSplitFromInterval());
- const RegisterInfo *pReg = platformRegister(*i);
- Q_ASSERT(pReg);
- _loads.push_back(generateUnspill(i->temp(), pReg->reg<int>()));
- }
-
- if (i->reg() != LifeTimeInterval::InvalidRegister &&
- (i->covers(defPosition(_currentStmt)) ||
- i->covers(usePosition(_currentStmt)))) {
- const RegisterInfo *pReg = platformRegister(*i);
- Q_ASSERT(pReg);
- t->kind = Temp::PhysicalRegister;
- t->index = pReg->reg<unsigned>();
- } else {
- int stackSlot = _assignedSpillSlots[t->index];
- Q_ASSERT(stackSlot >= 0);
- t->kind = Temp::StackSlot;
- t->index = stackSlot;
- }
- }
-
- void visit(Stmt *s)
- {
- switch (s->stmtKind) {
- case Stmt::MoveStmt: {
- auto m = s->asMove();
- if (Temp *t = m->target->asTemp())
- maybeGenerateSpill(t);
-
- visit(m->source);
- visit(m->target);
- } break;
- case Stmt::PhiStmt: {
- auto p = s->asPhi();
- maybeGenerateSpill(p->targetTemp);
- } break;
- default:
- STMT_VISIT_ALL_KINDS(s);
- break;
- }
- }
-};
-} // anonymous namespace
-
-RegisterAllocator::RegisterAllocator(const QV4::JIT::RegisterInformation &registerInformation)
- : _registerInformation(registerInformation)
-{
- for (int i = 0, ei = registerInformation.size(); i != ei; ++i) {
- const RegisterInfo &regInfo = registerInformation.at(i);
- if (regInfo.useForRegAlloc()) {
- if (regInfo.isRegularRegister())
- _normalRegisters.append(&regInfo);
- else
- _fpRegisters.append(&regInfo);
- }
- }
- Q_ASSERT(_normalRegisters.size() >= 2);
- Q_ASSERT(_fpRegisters.size() >= 2);
- _active.reserve((_normalRegisters.size() + _fpRegisters.size()) * 2);
- _inactive.reserve(_active.size());
-
- _regularRegsInUse.resize(_normalRegisters.size());
- _fpRegsInUse.resize(_fpRegisters.size());
-}
-
-RegisterAllocator::~RegisterAllocator()
-{
-}
-
-void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
-{
- _lastAssignedRegister.assign(function->tempCount, LifeTimeInterval::InvalidRegister);
- _assignedSpillSlots.assign(function->tempCount, InvalidSpillSlot);
- _activeSpillSlots.resize(function->tempCount);
-
- if (DebugRegAlloc)
- qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
-
- _lifeTimeIntervals = opt.lifeTimeIntervals();
-
- _unhandled = _lifeTimeIntervals->intervals();
- _handled.reserve(_unhandled.size());
-
- _info.reset(new RegAllocInfo);
- _info->collect(function, _lifeTimeIntervals);
-
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Ranges:" << endl;
- QVector<LifeTimeInterval *> intervals = _unhandled;
- std::reverse(intervals.begin(), intervals.end());
- for (const LifeTimeInterval *r : qAsConst(intervals)) {
- r->dump(qout);
- qout << endl;
- }
- qDebug("%s", buf.data().constData());
- _info->dump();
-
- qDebug() << "*** Before register allocation:";
- buf.setData(QByteArray());
- IRPrinterWithPositions(&qout, _lifeTimeIntervals).print(function);
- qDebug("%s", buf.data().constData());
- }
- prepareRanges();
-
- linearScan();
-
- if (DebugRegAlloc)
- dump(function);
-
- // sort the ranges in reverse order, so the ResolutionPhase can take from the end (and thereby
- // prevent the copy overhead that taking from the beginning would give).
- std::sort(_handled.begin(), _handled.end(),
- [](const LifeTimeInterval *r1, const LifeTimeInterval *r2) -> bool {
- return LifeTimeInterval::lessThan(r2, r1);
- });
- ResolutionPhase(std::move(_handled), _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run();
-
- function->tempCount = *std::max_element(_assignedSpillSlots.begin(), _assignedSpillSlots.end()) + 1;
-
- if (DebugRegAlloc)
- qDebug() << "*** Finished regalloc , result:";
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_IR");
- if (showCode) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithRegisters(&qout, _lifeTimeIntervals, _registerInformation).print(function);
- qDebug("%s", buf.data().constData());
- }
-}
-
-RegisterInformation RegisterAllocator::usedRegisters() const
-{
- RegisterInformation regInfo;
-
- for (int i = 0, ei = _normalRegisters.size(); i != ei; ++i) {
- if (_regularRegsInUse.testBit(i))
- regInfo.append(*_normalRegisters.at(i));
- }
-
- for (int i = 0, ei = _fpRegisters.size(); i != ei; ++i) {
- if (_fpRegsInUse.testBit(i))
- regInfo.append(*_fpRegisters.at(i));
- }
-
- return regInfo;
-}
-
-void RegisterAllocator::markInUse(int reg, bool isFPReg)
-{
- if (isFPReg)
- _fpRegsInUse.setBit(reg);
- else
- _regularRegsInUse.setBit(reg);
-}
-
-static inline LifeTimeInterval createFixedInterval(int rangeCount)
-{
- LifeTimeInterval i(rangeCount);
- i.setReg(0);
-
- Temp t;
- t.init(Temp::PhysicalRegister, 0);
- t.type = IR::SInt32Type;
- i.setTemp(t);
-
- return i;
-}
-
-LifeTimeInterval *RegisterAllocator::cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original)
-{
- LifeTimeInterval *lti = new LifeTimeInterval(original);
- _lifeTimeIntervals->add(lti);
- lti->setReg(reg);
- lti->setFixedInterval(true);
-
- Temp t;
- t.init(Temp::PhysicalRegister, reg);
- t.type = isFP ? IR::DoubleType : IR::SInt32Type;
- lti->setTemp(t);
-
- return lti;
-}
-
-// Creates the intervals with fixed ranges. See [Wimmer2]. Note that this only applies to callee-
-// saved registers.
-void RegisterAllocator::prepareRanges()
-{
- LifeTimeInterval ltiWithCalls = createFixedInterval(int(_info->calls().size()));
- for (int callPosition : _info->calls())
- ltiWithCalls.addRange(callPosition, callPosition);
-
- const int regCount = _normalRegisters.size();
- _fixedRegisterRanges.resize(regCount);
- for (int reg = 0; reg < regCount; ++reg) {
- if (_normalRegisters.at(reg)->isCallerSaved()) {
- LifeTimeInterval *lti = cloneFixedInterval(reg, false, ltiWithCalls);
- if (lti->isValid()) {
- _fixedRegisterRanges[reg] = lti;
- _active.append(lti);
- }
- }
- }
-
- const int fpRegCount = _fpRegisters.size();
- _fixedFPRegisterRanges.resize(fpRegCount);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) {
- if (_fpRegisters.at(fpReg)->isCallerSaved()) {
- LifeTimeInterval *lti = cloneFixedInterval(fpReg, true, ltiWithCalls);
- if (lti->isValid()) {
- _fixedFPRegisterRanges[fpReg] = lti;
- _active.append(lti);
- }
- }
- }
-}
-
-void RegisterAllocator::linearScan()
-{
- while (!_unhandled.isEmpty()) {
- LifeTimeInterval *current = _unhandled.back();
- _unhandled.pop_back();
- const int position = current->start();
-
- // check for intervals in active that are handled or inactive
- for (int i = 0; i < _active.size(); ) {
- LifeTimeInterval *it = _active.at(i);
- if (it->end() < position) {
- if (!it->isFixedInterval())
- _handled += it;
- _active.remove(i);
- } else if (!it->covers(position)) {
- _inactive += it;
- _active.remove(i);
- } else {
- ++i;
- }
- }
-
- // check for intervals in inactive that are handled or active
- for (int i = 0; i < _inactive.size(); ) {
- LifeTimeInterval *it = _inactive.at(i);
- if (it->end() < position) {
- if (!it->isFixedInterval())
- _handled += it;
- _inactive.remove(i);
- } else if (it->covers(position)) {
- if (it->reg() != LifeTimeInterval::InvalidRegister) {
- _active += it;
- _inactive.remove(i);
- } else {
- // although this interval is now active, it has no register allocated (always
- // spilled), so leave it in inactive.
- ++i;
- }
- } else {
- ++i;
- }
- }
-
- Q_ASSERT(!current->isFixedInterval());
-
-#ifdef DEBUG_REGALLOC
- qDebug() << "** Position" << position;
-#endif // DEBUG_REGALLOC
-
- if (_info->canHaveRegister(current->temp())) {
- tryAllocateFreeReg(*current);
- if (current->reg() == LifeTimeInterval::InvalidRegister)
- allocateBlockedReg(*current);
- if (current->reg() != LifeTimeInterval::InvalidRegister)
- _active += current;
- } else {
- assignSpillSlot(current->temp(), current->start(), current->end());
- _inactive += current;
- if (DebugRegAlloc)
- qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current->temp().index]
- << "for %" << current->temp().index << "as it cannot be loaded in a register";
- }
- }
-
- for (LifeTimeInterval *r : qAsConst(_active))
- if (!r->isFixedInterval())
- _handled.append(r);
- _active.clear();
- for (LifeTimeInterval *r : qAsConst(_inactive))
- if (!r->isFixedInterval())
- _handled.append(r);
- _inactive.clear();
-}
-
-static inline int indexOfRangeCoveringPosition(const LifeTimeInterval::Ranges &ranges, int position)
-{
- for (int i = 0, ei = ranges.size(); i != ei; ++i) {
- if (position <= ranges[i].end)
- return i;
- }
- return -1;
-}
-
-static inline int intersectionPosition(const LifeTimeIntervalRange &one, const LifeTimeIntervalRange &two)
-{
- if (one.covers(two.start))
- return two.start;
- if (two.covers(one.start))
- return one.start;
- return -1;
-}
-
-static inline bool isFP(const Temp &t)
-{ return t.type == DoubleType; }
-
-static inline bool candidateIsBetterFit(int bestSizeSoFar, int idealSize, int candidateSize)
-{
- // If the candidateSize is larger than the current we take it only if the current size does not
- // yet fit for the whole interval.
- if (bestSizeSoFar < candidateSize && bestSizeSoFar < idealSize)
- return true;
-
- // If the candidateSize is smaller we only take it if it still fits the whole interval.
- if (bestSizeSoFar > candidateSize && candidateSize >= idealSize)
- return true;
-
- // Other wise: no luck.
- return false;
-}
-
-// Out of all available registers (with their next-uses), choose the one that fits the requested
-// duration best. This can return a register that is not free for the whole interval, but that's
-// fine: we just have to split the current interval.
-static void longestAvailableReg(int *nextUses, int nextUseCount, int &reg, int &freeUntilPos_reg, int lastUse)
-{
- reg = LifeTimeInterval::InvalidRegister;
- freeUntilPos_reg = 0;
-
- for (int candidate = 0, candidateEnd = nextUseCount; candidate != candidateEnd; ++candidate) {
- int fp = nextUses[candidate];
- if (candidateIsBetterFit(freeUntilPos_reg, lastUse, fp)) {
- reg = candidate;
- freeUntilPos_reg = fp;
- }
- }
-}
-
-#define CALLOC_ON_STACK(ty, ptr, sz, val) \
- Q_ASSERT(sz > 0); \
- Q_ALLOCA_VAR(ty, ptr, sizeof(ty) * (sz)); \
- for (ty *it = ptr, *eit = ptr + (sz); it != eit; ++it) \
- *it = val;
-
-// Try to allocate a register that's currently free.
-void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval &current)
-{
- Q_ASSERT(!current.isFixedInterval());
- Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister);
-
- const bool needsFPReg = isFP(current.temp());
- const int freeUntilPosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size();
- CALLOC_ON_STACK(int, freeUntilPos, freeUntilPosCount, INT_MAX);
-
- for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) {
- const LifeTimeInterval *it = *i;
- if (it->isFP() == needsFPReg)
- freeUntilPos[it->reg()] = 0; // mark register as unavailable
- }
-
- for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) {
- const LifeTimeInterval *it = *i;
- if (it->isFP() != needsFPReg)
- continue; // different register type, so not applicable.
- if (it->reg() == LifeTimeInterval::InvalidRegister)
- continue; // this range does not block a register from being used, as it has no register assigned
-
- if (current.isSplitFromInterval() || it->isFixedInterval()) {
- const int intersectionPos = nextIntersection(current, *it);
- if (intersectionPos != -1)
- freeUntilPos[it->reg()] = qMin(freeUntilPos[it->reg()], intersectionPos);
- }
- }
-
- int reg = LifeTimeInterval::InvalidRegister;
- int freeUntilPos_reg = 0;
-
- const RegAllocInfo::Hints &hints = _info->hints(current.temp());
- for (RegAllocInfo::Hints::const_iterator i = hints.begin(), ei = hints.end(); i != ei; ++i) {
- const Temp &hint = *i;
- int candidate;
- if (hint.kind == Temp::PhysicalRegister)
- candidate = hint.index;
- else
- candidate = _lastAssignedRegister[hint.index];
-
- const int end = current.end();
- if (candidate == LifeTimeInterval::InvalidRegister)
- continue; // the candidate has no register assigned, so it cannot be (re-)used
- if (current.isFP() != isFP(hint))
- continue; // different register type, so not applicable.
-
- const int fp = freeUntilPos[candidate];
- if (candidateIsBetterFit(freeUntilPos_reg, end, fp)) {
- reg = candidate;
- freeUntilPos_reg = fp;
- }
- }
-
- // None of the hinted registers could fit the interval, so try all registers next.
- if (reg == LifeTimeInterval::InvalidRegister)
- longestAvailableReg(freeUntilPos, freeUntilPosCount, reg, freeUntilPos_reg, current.end());
-
- if (freeUntilPos_reg == 0) {
- // no register available without spilling
- if (DebugRegAlloc)
- qDebug("*** no register available for %u", current.temp().index);
- return;
- } else if (current.end() < freeUntilPos_reg) {
- // register available for the whole interval
- if (DebugRegAlloc)
- qDebug() << "*** allocating register" << reg << "for the whole interval of %" << current.temp().index;
- current.setReg(reg);
- _lastAssignedRegister[current.temp().index] = reg;
- markInUse(reg, needsFPReg);
- } else {
- // register available for the first part of the interval
-
- // TODO: this is slightly inefficient in the following case:
- // %1 = something
- // some_call(%1)
- // %2 = %1 + 1
- // Now %1 will get a register assigned, and will be spilled to the stack immediately. It
- // would be better to check if there are actually uses in the range before the split.
-
- current.setReg(reg);
- _lastAssignedRegister[current.temp().index] = reg;
- if (DebugRegAlloc)
- qDebug() << "*** allocating register" << reg << "for the first part of interval of %" << current.temp().index;
- split(current, freeUntilPos_reg, true);
- markInUse(reg, needsFPReg);
- }
-}
-
-// This gets called when all registers are currently in use.
-void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current)
-{
- Q_ASSERT(!current.isFixedInterval());
- Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister);
- const int position = current.start();
-
- const bool isPhiTarget = _info->isPhiTarget(current.temp());
- if (isPhiTarget && !current.isSplitFromInterval()) {
- // Special case: storing to a phi-node's target will result in a single move. So, if we
- // would spill another interval to the stack (that's 1 store), and then do the move for the
- // phi target (at least 1 move or a load), that would result in 2 instructions. Instead, we
- // force the phi-node's target to go to the stack immediately, which is always a single
- // store.
- split(current, position + 1, true);
- _inactive.append(&current);
- return;
- }
-
- const bool needsFPReg = isFP(current.temp());
- const int nextUsePosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size();
- CALLOC_ON_STACK(int, nextUsePos, nextUsePosCount, INT_MAX);
- QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePosCount, 0);
-
- for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) {
- LifeTimeInterval &it = **i;
- if (it.isFP() != needsFPReg)
- continue; // different register type, so not applicable.
-
- const int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.start());
- if (nu == position) {
- nextUsePos[it.reg()] = 0;
- } else if (nu != -1 && nu < nextUsePos[it.reg()]) {
- nextUsePos[it.reg()] = nu;
- nextUseRangeForReg[it.reg()] = &it;
- } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) {
- // in a loop, the range can be active, but the result might only be used before the
- // current position (e.g. the induction variable being used in the phi node in the loop
- // header). So, we can use this register, but we need to remember to split the interval
- // in order to have the edge-resolving generate a load at the edge going back to the
- // loop header.
- nextUseRangeForReg[it.reg()] = &it;
- }
- }
-
- for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) {
- LifeTimeInterval &it = **i;
- if (it.isFP() != needsFPReg)
- continue; // different register type, so not applicable.
- if (it.reg() == LifeTimeInterval::InvalidRegister)
- continue; // this range does not block a register from being used, as it has no register assigned
-
- if (current.isSplitFromInterval() || it.isFixedInterval()) {
- if (nextIntersection(current, it) != -1) {
- const int nu = nextUse(it.temp(), current.start());
- if (nu != -1 && nu < nextUsePos[it.reg()]) {
- nextUsePos[it.reg()] = nu;
- nextUseRangeForReg[it.reg()] = &it;
- }
- }
- }
- }
-
- int reg, nextUsePos_reg;
- longestAvailableReg(nextUsePos, nextUsePosCount, reg, nextUsePos_reg, current.end());
-
- Q_ASSERT(current.start() <= nextUsePos_reg);
-
- // spill interval that currently block reg
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream out(&buf);
- out << "*** spilling intervals that block reg " <<reg<< " for interval ";
- current.dump(out);
- qDebug("%s", buf.data().constData());
- }
- current.setReg(reg);
- _lastAssignedRegister[current.temp().index] = reg;
- LifeTimeInterval *nextUse = nextUseRangeForReg[reg];
- Q_ASSERT(nextUse);
- Q_ASSERT(!nextUse->isFixedInterval());
-
- split(*nextUse, position, /*skipOptionalRegisterUses =*/ true);
-
- // We might have chosen a register that is used by a range that has a hole in its life time.
- // If that's the case, check if the current interval completely fits in the hole. Or rephrased:
- // check if the current interval will use the register after that hole ends (so that range, and
- // if so, split that interval so that it gets a new register assigned when it needs one.
- splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
-
- // make sure that current does not intersect with the fixed interval for reg
- const LifeTimeInterval *fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg)
- : _fixedRegisterRanges.at(reg);
- if (fixedRegRange) {
- int ni = nextIntersection(current, *fixedRegRange);
- if (ni != -1) {
- if (DebugRegAlloc) {
- qDebug("***-- current range intersects with a fixed reg use at %d, so splitting it.", ni);
- }
- // current does overlap with a fixed interval, so split current before that intersection.
- split(current, ni, true);
- }
- }
-}
-
-int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
- const LifeTimeInterval &another) const
-{
- const LifeTimeInterval::Ranges &currentRanges = current.ranges();
- int currentIt = 0;
-
- const LifeTimeInterval::Ranges &anotherRanges = another.ranges();
- const int anotherItStart = indexOfRangeCoveringPosition(anotherRanges, current.start());
- if (anotherItStart == -1)
- return -1;
-
- for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) {
- const LifeTimeIntervalRange currentRange = currentRanges.at(currentIt);
- for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) {
- const LifeTimeIntervalRange anotherRange = anotherRanges.at(anotherIt);
- if (anotherRange.start > currentRange.end)
- break;
- int intersectPos = intersectionPosition(currentRange, anotherRange);
- if (intersectPos != -1)
- return intersectPos;
- }
- }
-
- return -1;
-}
-
-/// Find the first use after the start position for the given temp.
-///
-/// This is only called when all registers are in use, and when one of them has to be spilled to the
-/// stack. So, uses where a register is optional can be ignored.
-int RegisterAllocator::nextUse(const Temp &t, int startPosition) const
-{
- typedef std::vector<Use>::const_iterator ConstIt;
-
- const std::vector<Use> &usePositions = _info->uses(t);
- const ConstIt cend = usePositions.end();
- for (ConstIt it = usePositions.begin(); it != cend; ++it) {
- if (it->mustHaveRegister()) {
- const int usePos = it->pos;
- if (usePos >= startPosition)
- return usePos;
- }
- }
-
- return -1;
-}
-
-static inline void insertReverseSorted(QVector<LifeTimeInterval *> &intervals, LifeTimeInterval *newInterval)
-{
- newInterval->validate();
- for (int i = intervals.size(); i > 0;) {
- if (LifeTimeInterval::lessThan(newInterval, intervals.at(--i))) {
- intervals.insert(i + 1, newInterval);
- return;
- }
- }
- intervals.insert(0, newInterval);
-}
-
-void RegisterAllocator::split(LifeTimeInterval &current, int beforePosition,
- bool skipOptionalRegisterUses)
-{ // TODO: check if we can always skip the optional register uses
- Q_ASSERT(!current.isFixedInterval());
-
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream out(&buf);
- out << "***** split request for range ";
- current.dump(out);
- out << " before position " << beforePosition
- << " and skipOptionalRegisterUses = " << skipOptionalRegisterUses << endl;
- qDebug("%s", buf.data().constData());
- }
-
- assignSpillSlot(current.temp(), current.start(), current.end());
-
- const int firstPosition = current.start();
- Q_ASSERT(beforePosition > firstPosition && "split before start");
-
- int lastUse = firstPosition;
- int nextUse = -1;
- const std::vector<Use> &usePositions = _info->uses(current.temp());
- for (size_t i = 0, ei = usePositions.size(); i != ei; ++i) {
- const Use &usePosition = usePositions.at(i);
- const int usePos = usePosition.pos;
- if (lastUse < usePos && usePos < beforePosition) {
- lastUse = usePos;
- } else if (usePos >= beforePosition) {
- if (!skipOptionalRegisterUses || usePosition.mustHaveRegister()) {
- nextUse = usePos;
- break;
- }
- }
- }
- Q_ASSERT(lastUse != -1);
- Q_ASSERT(lastUse < beforePosition);
-
- LifeTimeInterval newInterval = current.split(lastUse, nextUse);
- if (DebugRegAlloc) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream out(&buf);
- out << "***** last use = " << lastUse << ", nextUse = " << nextUse << endl;
- out << "***** new interval: ";
- newInterval.dump(out);
- out << endl;
- out << "***** preceding interval: ";
- current.dump(out);
- out << endl;
- qDebug("%s", buf.data().constData());
- }
- if (newInterval.isValid()) {
- if (current.reg() != LifeTimeInterval::InvalidRegister)
- _info->addHint(current.temp(), current.reg());
- newInterval.setReg(LifeTimeInterval::InvalidRegister);
- LifeTimeInterval *newIntervalPtr = new LifeTimeInterval(newInterval);
- _lifeTimeIntervals->add(newIntervalPtr);
- insertReverseSorted(_unhandled, newIntervalPtr);
- }
-}
-
-void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position)
-{
- for (int i = 0, ei = _inactive.size(); i != ei; ++i) {
- LifeTimeInterval &interval = *_inactive[i];
- if (interval.isFixedInterval())
- continue;
- if (isFPReg == interval.isFP() && interval.reg() == reg) {
- LifeTimeInterval::Ranges ranges = interval.ranges();
- int endOfLifetimeHole = -1;
- for (int j = 0, ej = ranges.size(); j != ej; ++j) {
- if (position < ranges[j].start)
- endOfLifetimeHole = ranges[j].start;
- }
- if (endOfLifetimeHole != -1)
- split(interval, endOfLifetimeHole);
- }
- }
-}
-
-void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos)
-{
- if (_assignedSpillSlots[t.index] != InvalidSpillSlot)
- return;
-
- for (int i = 0, ei = _activeSpillSlots.size(); i != ei; ++i) {
- if (_activeSpillSlots.at(i) < startPos) {
- _activeSpillSlots[i] = endPos;
- _assignedSpillSlots[t.index] = i;
- return;
- }
- }
-
- Q_UNREACHABLE();
-}
-
-void RegisterAllocator::dump(IR::Function *function) const
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- IRPrinterWithPositions printer(&qout, _lifeTimeIntervals);
-
- qout << "Ranges:" << endl;
- QVector<LifeTimeInterval *> handled = _handled;
- std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp);
- for (const LifeTimeInterval *r : qAsConst(handled)) {
- r->dump(qout);
- qout << endl;
- }
-
- qout << "Spill slots:" << endl;
- for (unsigned i = 0; i < _assignedSpillSlots.size(); ++i)
- if (_assignedSpillSlots[i] != InvalidSpillSlot)
- qout << "\t%" << i << " -> " << _assignedSpillSlots[i] << endl;
-
- printer.print(function);
- qDebug("%s", buf.data().constData());
-}
-
-// References:
-// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of
-// CGO'10, ACM Press, 2010
-// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register
-// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual
-// Execution Environments, pages 132-141. ACM Press, 2005.
-// [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan
-// Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming
-// Language Design and Implementation, pages 142-151, June 1998.
diff --git a/src/qml/jit/qv4regalloc_p.h b/src/qml/jit/qv4regalloc_p.h
deleted file mode 100644
index 4ee440b73e..0000000000
--- a/src/qml/jit/qv4regalloc_p.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the V4VM module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and 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 QV4REGALLOC_P_H
-#define QV4REGALLOC_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 "qv4global_p.h"
-#include "qv4isel_p.h"
-#include "qv4ssa_p.h"
-#include "qv4registerinfo_p.h"
-
-#include <config.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-class RegAllocInfo;
-
-// This class implements a linear-scan register allocator, with a couple of tweaks:
-// - Second-chance allocation is used when an interval becomes active after a spill, which results
-// in fewer differences between edges, and hence fewer moves before jumps.
-// - Use positions are flagged with either "must have" register or "could have" register. This is
-// used to decide whether a register is really needed when a temporary is used after a spill
-// occurred.
-// - Fixed intervals are used to denotate IR positions where certain registers are needed in order
-// to implement the operation, and cannot be used by a temporary on that position. An example is
-// caller saved registers, where the call will use/clobber those registers.
-// - Hints are used to indicate which registers could be used to generate more compact code. An
-// example is an addition, where one (or both) operands' life-time ends at that instruction. In
-// this case, re-using an operand register for the result will result in an in-place add.
-// - SSA form properties are used:
-// - to simplify life-times (two temporaries will never interfere as long as their intervals
-// are not split), resulting in a slightly faster algorithm;
-// - when a temporary needs to be spilled, it is done directly after calculating it, so that
-// 1 store is generated even if multiple spills/splits happen.
-// - phi-node elimination (SSA form deconstruction) is done when resolving differences between
-// CFG edges
-class RegisterAllocator
-{
- typedef IR::LifeTimeInterval LifeTimeInterval;
-
- const RegisterInformation &_registerInformation;
- QVector<const RegisterInfo *> _normalRegisters;
- QVector<const RegisterInfo *> _fpRegisters;
- QScopedPointer<RegAllocInfo> _info;
-
- QVector<LifeTimeInterval *> _fixedRegisterRanges, _fixedFPRegisterRanges;
-
- IR::LifeTimeIntervals::Ptr _lifeTimeIntervals;
- typedef QVector<LifeTimeInterval *> Intervals;
- Intervals _unhandled, _active, _inactive, _handled;
-
- std::vector<int> _lastAssignedRegister;
- std::vector<int> _assignedSpillSlots;
- QVector<int> _activeSpillSlots;
-
- QBitArray _regularRegsInUse, _fpRegsInUse;
-
- Q_DISABLE_COPY(RegisterAllocator)
-
-public:
- enum { InvalidSpillSlot = -1 };
-
- RegisterAllocator(const RegisterInformation &registerInformation);
- ~RegisterAllocator();
-
- void run(IR::Function *function, const IR::Optimizer &opt);
- RegisterInformation usedRegisters() const;
-
-private:
- void markInUse(int reg, bool isFPReg);
- LifeTimeInterval *cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original);
- void prepareRanges();
- void linearScan();
- void tryAllocateFreeReg(LifeTimeInterval &current);
- void allocateBlockedReg(LifeTimeInterval &current);
- int nextIntersection(const LifeTimeInterval &current, const LifeTimeInterval &another) const;
- int nextUse(const IR::Temp &t, int startPosition) const;
- void split(LifeTimeInterval &current, int beforePosition, bool skipOptionalRegisterUses =false);
- void splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position);
- void assignSpillSlot(const IR::Temp &t, int startPos, int endPos);
- void resolve(IR::Function *function, const IR::Optimizer &opt);
-
- void dump(IR::Function *function) const;
-};
-
-} // end of namespace JIT
-} // end of namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4REGALLOC_P_H
diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h
deleted file mode 100644
index 214206db91..0000000000
--- a/src/qml/jit/qv4registerinfo_p.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4REGISTERINFO_P_H
-#define QV4REGISTERINFO_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 <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-class RegisterInfo
-{
-public:
- enum { InvalidRegister = (1 << 29) - 1 };
- enum SavedBy { CallerSaved, CalleeSaved };
- enum RegisterType { RegularRegister, FloatingPointRegister };
- enum Usage { Predefined, RegAlloc };
-
-public:
- RegisterInfo()
- : _savedBy(CallerSaved)
- , _usage(Predefined)
- , _type(RegularRegister)
- , _reg(InvalidRegister)
- {}
-
- RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage)
- : _prettyName(prettyName)
- , _savedBy(savedBy)
- , _usage(usage)
- , _type(type)
- , _reg(reg)
- {}
-
- bool operator==(const RegisterInfo &other) const
- { return _type == other._type && _reg == other._reg; }
-
- bool isValid() const { return _reg != InvalidRegister; }
- template <typename T> T reg() const { return static_cast<T>(_reg); }
- QString prettyName() const { return _prettyName; }
- bool isCallerSaved() const { return _savedBy == CallerSaved; }
- bool isCalleeSaved() const { return _savedBy == CalleeSaved; }
- bool isFloatingPoint() const { return _type == FloatingPointRegister; }
- bool isRegularRegister() const { return _type == RegularRegister; }
- bool useForRegAlloc() const { return _usage == RegAlloc; }
- bool isPredefined() const { return _usage == Predefined; }
-
-private:
- QString _prettyName;
- unsigned _savedBy : 1;
- unsigned _usage : 1;
- unsigned _type : 1;
- unsigned _reg : 29;
-};
-typedef QVector<RegisterInfo> RegisterInformation;
-
-} // JIT namespace
-} // QV4 namespace
-
-QT_END_NAMESPACE
-
-#endif // QV4REGISTERINFO_P_H
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
deleted file mode 100644
index 6d788f4a93..0000000000
--- a/src/qml/jit/qv4targetplatform_p.h
+++ /dev/null
@@ -1,707 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4TARGETPLATFORM_P_H
-#define QV4TARGETPLATFORM_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 <config.h>
-
-#if ENABLE(ASSEMBLER)
-
-#include <private/qv4value_p.h>
-#include "qv4registerinfo_p.h"
-#include <assembler/MacroAssembler.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace JIT {
-
-enum TargetOperatingSystemSpecialization {
- NoOperatingSystemSpecialization,
- WindowsSpecialization
-};
-
-// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
-//
-// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
-// - Linux/x86 and win32, which are the same, except that linux non-PIC/PIE code does not need to
-// restore ebx (which holds the GOT ptr) before a call
-// - All (supported) ARM platforms, where the only variety is the platform specific usage of r9,
-// and the frame-pointer in Thumb/Thumb2 v.s. ARM mode.
-//
-// Specific handling of ebx when it holds the GOT:
-// In this case we can use it, but it needs to be restored when doing a call. So, the handling is as
-// follows: it is marked as caller saved, meaning the value in it won't survive a call. When
-// calculating the list of callee saved registers in getCalleeSavedRegisters (which is used to
-// generate push/pop instructions in the prelude/postlude), we add ebx too. Then when synthesizing
-// a call, we add a load it right before emitting the call instruction.
-//
-// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h!
-template <typename PlatformAssembler, TargetOperatingSystemSpecialization specialization = NoOperatingSystemSpecialization>
-class TargetPlatform
-{
-};
-
-#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD) || defined(Q_OS_IOS))
-template <>
-class TargetPlatform<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerX86;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
-
- enum { RegAllocIsSupported = 1 };
-
- static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const RegisterID EngineRegister = JSC::X86Registers::esi;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static const RegisterID LowReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID HighReturnValueRegister = JSC::X86Registers::edx;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- << RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::esi, QStringLiteral("esi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
- static const int RegisterSize = 4;
-
- static const int RegisterArgumentCount = 0;
- static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
-
- static const int StackAlignment = 16;
- static const int StackShadowSpace = 0;
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0)
- as->add32(TrustedImm32(frameSize), StackPointerRegister);
- as->pop(FramePointerRegister);
- }
-
-#if OS(WINDOWS) || OS(QNX) || \
- ((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
-
- static const int gotRegister = JSC::X86Registers::ebx;
- static int savedGOTRegisterSlotOnStack() {
- static int ebxIdx = -1;
- if (ebxIdx == -1) {
- int calleeSaves = 0;
- const auto infos = getRegisterInfo();
- for (const RegisterInfo &info : infos) {
- if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
- ebxIdx = calleeSaves;
- break;
- } else if (info.isCalleeSaved()) {
- ++calleeSaves;
- }
- }
- Q_ASSERT(ebxIdx >= 0);
- ebxIdx += 1;
- }
- return ebxIdx * -int(sizeof(void*));
- }
-#else
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-#endif
-};
-#endif // x86
-
-#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || OS(QNX) || defined(Q_OS_IOS))
-template <>
-class TargetPlatform<JSC::MacroAssemblerX86_64, NoOperatingSystemSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerX86_64;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
-
- enum { RegAllocIsSupported = 1 };
-
- static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const RegisterID EngineRegister = JSC::X86Registers::r14;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- // r11 is used as scratch register by the macro assembler
- << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
- static const int RegisterSize = 8;
-
- static const int RegisterArgumentCount = 6;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::X86Registers::edi,
- JSC::X86Registers::esi,
- JSC::X86Registers::edx,
- JSC::X86Registers::ecx,
- JSC::X86Registers::r8,
- JSC::X86Registers::r9
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
-
- static const int StackAlignment = 16;
- static const int StackShadowSpace = 0;
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
- {
- as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
- }
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0)
- as->add64(TrustedImm32(frameSize), StackPointerRegister);
- as->pop(FramePointerRegister);
- }
-
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-};
-#endif // Linux/MacOS on x86_64
-
-#if CPU(X86_64) && OS(WINDOWS)
-template <>
-class TargetPlatform<JSC::MacroAssemblerX86_64, WindowsSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerX86_64;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
-
- enum { RegAllocIsSupported = 1 };
-
- static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const RegisterID EngineRegister = JSC::X86Registers::r14;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- // r11 is used as scratch register by the macro assembler
- << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
- static const int RegisterSize = 8;
-
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::X86Registers::ecx,
- JSC::X86Registers::edx,
- JSC::X86Registers::r8,
- JSC::X86Registers::r9
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- }
-
- static const int StackAlignment = 16;
- static const int StackShadowSpace = 32;
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
- {
- as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
- }
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0)
- as->add64(TrustedImm32(frameSize), StackPointerRegister);
- as->pop(FramePointerRegister);
- }
-
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-};
-#endif // Windows on x86_64
-
-#if CPU(ARM) || defined(V4_BOOTSTRAP)
-template <>
-class TargetPlatform<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerARMv7;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
-
- enum { RegAllocIsSupported = 1 };
-
- // The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
- // - The GNU/Linux ABI defines it as an additional callee-saved variable register (v6).
- // - iOS (for which we cannot JIT, but still...) defines it as having a special use, so we do
- // not touch it, nor use it.
- // - Any other platform has not been verified, so we conservatively assume we cannot use it.
-#if OS(LINUX)
-#define CAN_USE_R9
-#endif
-
- // There are two designated frame-pointer registers on ARM, depending on which instruction set
- // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
- // accordingly, and assign the locals-register to the "other" register.
-#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
- static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
- static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
-#else // Thumbs down
- static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
- static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
-#endif
- static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
- static const RegisterID ScratchRegister = JSC::ARMRegisters::r5;
- static const RegisterID EngineRegister = JSC::ARMRegisters::r10;
- static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
- static const RegisterID LowReturnValueRegister = JSC::ARMRegisters::r0;
- static const RegisterID HighReturnValueRegister = JSC::ARMRegisters::r1;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- << RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
- << RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::r3, QStringLiteral("r3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
- << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#endif
- << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
-#ifdef CAN_USE_R9
- << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
-#endif
- << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
- << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#endif
- << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d3, QStringLiteral("d3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d4, QStringLiteral("d4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d5, QStringLiteral("d5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d6, QStringLiteral("d6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d8, QStringLiteral("d8"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d9, QStringLiteral("d9"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d10, QStringLiteral("d10"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d11, QStringLiteral("d11"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d12, QStringLiteral("d12"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d13, QStringLiteral("d13"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d14, QStringLiteral("d14"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARMRegisters::d15, QStringLiteral("d15"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
- static const int RegisterSize = 4;
-
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::ARMRegisters::r0,
- JSC::ARMRegisters::r1,
- JSC::ARMRegisters::r2,
- JSC::ARMRegisters::r3
- };
-
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
-
- static const int StackAlignment = 8; // Per AAPCS
- static const int StackShadowSpace = 0;
- static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
-
- static void platformEnterStandardStackFrame(PlatformAssembler *as)
- {
- as->push(JSC::ARMRegisters::lr);
- as->push(FramePointerRegister);
- }
-
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
-
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0) {
- // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
- // work well for large immediates.
- as->move(TrustedImm32(frameSize), JSC::ARMRegisters::r3);
- as->add32(JSC::ARMRegisters::r3, StackPointerRegister);
- }
- as->pop(FramePointerRegister);
- as->pop(JSC::ARMRegisters::lr);
- }
-
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-};
-#endif // ARM (32 bit)
-
-#if CPU(ARM64) || defined(V4_BOOTSTRAP)
-template <>
-class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerARM64;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
-
- enum { RegAllocIsSupported = 1 };
-
- static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
- static const RegisterID LocalsRegister = JSC::ARM64Registers::x28;
- static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
- static const RegisterID ScratchRegister = JSC::ARM64Registers::x9;
- static const RegisterID EngineRegister = JSC::ARM64Registers::x27;
- static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
- static const RegisterID DoubleMaskRegister = JSC::ARM64Registers::x26;
- static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
- static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- << RI(JSC::ARM64Registers::x0, QStringLiteral("x0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
- << RI(JSC::ARM64Registers::x1, QStringLiteral("x1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x2, QStringLiteral("x2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x3, QStringLiteral("x3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x4, QStringLiteral("x4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x5, QStringLiteral("x5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x6, QStringLiteral("x6"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x7, QStringLiteral("x7"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x8, QStringLiteral("x8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
- << RI(JSC::ARM64Registers::x9, QStringLiteral("x9"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::ARM64Registers::x10, QStringLiteral("x10"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x11, QStringLiteral("x11"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x12, QStringLiteral("x12"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x13, QStringLiteral("x13"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x14, QStringLiteral("x14"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x15, QStringLiteral("x15"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x19, QStringLiteral("x19"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x20, QStringLiteral("x20"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x21, QStringLiteral("x21"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x22, QStringLiteral("x22"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x23, QStringLiteral("x23"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x24, QStringLiteral("x24"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x25, QStringLiteral("x25"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::x26, QStringLiteral("x26"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::ARM64Registers::x27, QStringLiteral("x27"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::ARM64Registers::x28, QStringLiteral("x28"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-
- << RI(JSC::ARM64Registers::q2, QStringLiteral("q2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q3, QStringLiteral("q3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q4, QStringLiteral("q4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q5, QStringLiteral("q5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q6, QStringLiteral("q6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q8, QStringLiteral("q8"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q9, QStringLiteral("q9"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q10, QStringLiteral("q10"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q11, QStringLiteral("q11"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q12, QStringLiteral("q12"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q13, QStringLiteral("q13"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q14, QStringLiteral("q14"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q15, QStringLiteral("q15"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q16, QStringLiteral("q16"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q17, QStringLiteral("q17"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q18, QStringLiteral("q18"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q19, QStringLiteral("q19"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q20, QStringLiteral("q20"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q21, QStringLiteral("q21"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q22, QStringLiteral("q22"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q23, QStringLiteral("q23"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q24, QStringLiteral("q24"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q25, QStringLiteral("q25"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q26, QStringLiteral("q26"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q27, QStringLiteral("q27"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q28, QStringLiteral("q28"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q29, QStringLiteral("q29"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q30, QStringLiteral("q30"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::ARM64Registers::q31, QStringLiteral("q31"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
- static const int RegisterSize = 8;
-
- static const int RegisterArgumentCount = 8;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::ARM64Registers::x0,
- JSC::ARM64Registers::x1,
- JSC::ARM64Registers::x2,
- JSC::ARM64Registers::x3,
- JSC::ARM64Registers::x4,
- JSC::ARM64Registers::x5,
- JSC::ARM64Registers::x6,
- JSC::ARM64Registers::x7
- };
-
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
-
- static const int StackAlignment = 16;
- static const int StackShadowSpace = 0;
- static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
-
- static void platformEnterStandardStackFrame(PlatformAssembler *as)
- {
- as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
- }
-
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as)
- {
- as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister);
- }
-
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0)
- as->add64(TrustedImm32(frameSize), StackPointerRegister);
- as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
- }
-
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-};
-#endif // ARM64
-
-#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
-template <>
-class TargetPlatform<JSC::MacroAssemblerMIPS, NoOperatingSystemSpecialization>
-{
-public:
- using PlatformAssembler = JSC::MacroAssemblerMIPS;
- using RegisterID = PlatformAssembler::RegisterID;
- using FPRegisterID = PlatformAssembler::FPRegisterID;
- using TrustedImm32 = PlatformAssembler::TrustedImm32;
- enum { RegAllocIsSupported = 1 };
-
- static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
- static const RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
- static const RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
- static const RegisterID EngineRegister = JSC::MIPSRegisters::s1;
- static const RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
- static const RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
- static const FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
- static const FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
- static const RegisterID LowReturnValueRegister = JSC::MIPSRegisters::v0;
- static const RegisterID HighReturnValueRegister = JSC::MIPSRegisters::v1;
-
- static RegisterInformation getRegisterInfo()
- {
- typedef RegisterInfo RI;
- static RegisterInformation info = RegisterInformation()
- // Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS.
- << RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::t6, QStringLiteral("t6"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::t7, QStringLiteral("t7"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::t8, QStringLiteral("t8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::s0, QStringLiteral("s0"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::MIPSRegisters::s1, QStringLiteral("s1"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::MIPSRegisters::s2, QStringLiteral("s2"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
- << RI(JSC::MIPSRegisters::s3, QStringLiteral("s3"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f4, QStringLiteral("f4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f6, QStringLiteral("f6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f8, QStringLiteral("f8"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f10, QStringLiteral("f10"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f18, QStringLiteral("f18"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f20, QStringLiteral("f20"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f22, QStringLiteral("f22"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f24, QStringLiteral("f24"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- << RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
- ;
- return info;
- }
-
-#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
- static const int RegisterSize = 4;
-
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::MIPSRegisters::a0,
- JSC::MIPSRegisters::a1,
- JSC::MIPSRegisters::a2,
- JSC::MIPSRegisters::a3
- };
-
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
-
- static const int StackAlignment = 8;
- static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers.
- static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
-
- static void platformEnterStandardStackFrame(PlatformAssembler *as)
- {
- as->push(JSC::MIPSRegisters::ra);
- as->push(FramePointerRegister);
- }
-
- static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {}
-
- static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize)
- {
- if (frameSize > 0)
- as->add32(TrustedImm32(frameSize), StackPointerRegister);
- as->pop(FramePointerRegister);
- as->pop(JSC::MIPSRegisters::ra);
- }
-
-
- static const int gotRegister = -1;
- static int savedGOTRegisterSlotOnStack() { return -1; }
-};
-#endif // Linux on MIPS (32 bit)
-
-} // JIT namespace
-} // QV4 namespace
-
-QT_END_NAMESPACE
-
-#endif // ENABLE(ASSEMBLER)
-
-#endif // QV4TARGETPLATFORM_P_H
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
deleted file mode 100644
index 7ffa1c7151..0000000000
--- a/src/qml/jit/qv4unop.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 <qv4unop_p.h>
-#include <qv4assembler_p.h>
-
-#if ENABLE(ASSEMBLER)
-
-using namespace QV4;
-using namespace JIT;
-
-#define stringIfyx(s) #s
-#define stringIfy(s) stringIfyx(s)
-#define setOp(operation) \
- do { \
- call = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); name = "Runtime::" stringIfy(operation); \
- needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
- } while (0)
-
-template <typename JITAssembler>
-void Unop<JITAssembler>::generate(IR::Expr *source, IR::Expr *target)
-{
- bool needsExceptionCheck;
- typename JITAssembler::RuntimeCall call;
- const char *name = 0;
- switch (op) {
- case IR::OpNot:
- generateNot(source, target);
- return;
- case IR::OpUMinus:
- generateUMinus(source, target);
- return;
- case IR::OpUPlus: setOp(uPlus); break;
- case IR::OpCompl:
- generateCompl(source, target);
- return;
- case IR::OpPreIncrement: setOp(preIncrement); break;
- case IR::OpPreDecrement: setOp(preDecrement); break;
- default:
- Q_UNREACHABLE();
- } // switch
-
- Q_ASSERT(call.isValid());
- _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void Unop<JITAssembler>::generateUMinus(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *targetTemp = target->asTemp();
-
- if (IR::Const *c = source->asConst()) {
- if (c->value == 0 && source->type == IR::SInt32Type) {
- // special case: minus integer 0 is 0, which is not what JS expects it to be, so always
- // do a runtime call
- generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
- return;
- }
- }
- if (source->type == IR::SInt32Type) {
- typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (typename JITAssembler::RegisterID) targetTemp->index;
- typename JITAssembler::RegisterID sReg = _as->toInt32Register(source, tReg);
- _as->move(sReg, tReg);
- _as->neg32(tReg);
- if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- _as->storeInt32(tReg, target);
- return;
- }
-
- generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void Unop<JITAssembler>::generateNot(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *targetTemp = target->asTemp();
- if (source->type == IR::BoolType) {
- typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (typename JITAssembler::RegisterID) targetTemp->index;
- _as->xor32(TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
- if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- _as->storeBool(tReg, target);
- return;
- } else if (source->type == IR::SInt32Type) {
- typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (typename JITAssembler::RegisterID) targetTemp->index;
- _as->compare32(RelationalCondition::Equal,
- _as->toInt32Register(source, JITAssembler::ScratchRegister), TrustedImm32(0),
- tReg);
- if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- _as->storeBool(tReg, target);
- return;
- } else if (source->type == IR::DoubleType) {
- // ###
- }
- // ## generic implementation testing for int/bool
-
- generateRuntimeCall(_as, target, uNot, PointerToValue(source));
-}
-
-template <typename JITAssembler>
-void Unop<JITAssembler>::generateCompl(IR::Expr *source, IR::Expr *target)
-{
- IR::Temp *targetTemp = target->asTemp();
- if (source->type == IR::SInt32Type) {
- typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
- if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (typename JITAssembler::RegisterID) targetTemp->index;
- _as->xor32(TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
- if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
- _as->storeInt32(tReg, target);
- return;
- }
- generateRuntimeCall(_as, target, complement, PointerToValue(source));
-}
-
-template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
-#if defined(V4_BOOTSTRAP)
-#if !CPU(ARM_THUMB2)
-template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
-#endif
-#if !CPU(ARM64)
-template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>>;
-#endif
-#endif
-
-#endif
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
deleted file mode 100644
index fb68f80eec..0000000000
--- a/src/qml/jit/qv4unop_p.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 QV4UNOP_P_H
-#define QV4UNOP_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 <qv4jsir_p.h>
-#include <qv4isel_masm_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#if ENABLE(ASSEMBLER)
-
-namespace QV4 {
-namespace JIT {
-
-template <typename JITAssembler>
-struct Unop {
- Unop(JITAssembler *assembler, IR::AluOp operation)
- : _as(assembler)
- , op(operation)
- {}
-
- using RelationalCondition = typename JITAssembler::RelationalCondition;
- using PointerToValue = typename JITAssembler::PointerToValue;
- using RuntimeCall = typename JITAssembler::RuntimeCall;
- using TrustedImm32 = typename JITAssembler::TrustedImm32;
-
- void generate(IR::Expr *source, IR::Expr *target);
-
- void generateUMinus(IR::Expr *source, IR::Expr *target);
- void generateNot(IR::Expr *source, IR::Expr *target);
- void generateCompl(IR::Expr *source, IR::Expr *target);
-
- JITAssembler *_as;
- IR::AluOp op;
-};
-
-}
-}
-
-#endif
-
-QT_END_NAMESPACE
-
-#endif