aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit/qv4isel_masm.cpp
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/qv4isel_masm.cpp
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/qv4isel_masm.cpp')
-rw-r--r--src/qml/jit/qv4isel_masm.cpp1688
1 files changed, 0 insertions, 1688 deletions
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
-