diff options
Diffstat (limited to 'src/qml/jit/qv4isel_masm.cpp')
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 1201 |
1 files changed, 522 insertions, 679 deletions
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 20752b5c34..69d6951bb9 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -39,11 +39,7 @@ #include "qv4isel_masm_p.h" #include "qv4runtime_p.h" -#include "qv4object_p.h" -#include "qv4functionobject_p.h" -#include "qv4regexpobject_p.h" #include "qv4lookup_p.h" -#include "qv4function_p.h" #include "qv4ssa_p.h" #include "qv4regalloc_p.h" #include "qv4assembler_p.h" @@ -68,7 +64,8 @@ using namespace QV4; using namespace QV4::JIT; -InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory) +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) @@ -79,12 +76,14 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode; } -InstructionSelection::~InstructionSelection() +template <typename JITAssembler> +InstructionSelection<JITAssembler>::~InstructionSelection() { delete _as; } -void InstructionSelection::run(int functionIndex) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::run(int functionIndex) { IR::Function *function = irModule->functions[functionIndex]; qSwap(_function, function); @@ -93,8 +92,8 @@ void InstructionSelection::run(int functionIndex) opt.run(qmlEngine); static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC"); - if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { - RegisterAllocator regalloc(Assembler::getRegisterInfo()); + if (JITTargetPlatform::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { + RegisterAllocator regalloc(JITTargetPlatform::getRegisterInfo()); regalloc.run(_function, opt); calculateRegistersToSave(regalloc.usedRegisters()); } else { @@ -103,49 +102,24 @@ void InstructionSelection::run(int functionIndex) opt.convertOutOfSSA(); ConvertTemps().toStackSlots(_function); IR::Optimizer::showMeTheCode(_function, "After stack slot allocation"); - calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator. + 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); - Assembler* oldAssembler = _as; - _as = new Assembler(jsGenerator, _function, executableAllocator); + 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); -#ifdef ARGUMENTS_IN_REGISTERS - _as->move(_as->registerForArgument(0), Assembler::EngineRegister); -#else - _as->loadPtr(addressForArgument(0), Assembler::EngineRegister); -#endif - - const int locals = _as->stackLayout().calculateJSStackFrameSize(); - if (locals > 0) { - _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister); -#ifdef VALUE_FITS_IN_REGISTER - _as->move(Assembler::TrustedImm64(0), Assembler::ReturnValueRegister); - _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister); - Assembler::Label loop = _as->label(); - _as->store64(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister)); - _as->add64(Assembler::TrustedImm32(8), Assembler::LocalsRegister); - Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister); - jump.linkTo(loop, _as); -#else - _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister); - _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister); - Assembler::Label loop = _as->label(); - _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister)); - _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister); - _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister)); - _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister); - Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister); - jump.linkTo(loop, _as); -#endif - _as->storePtr(Assembler::LocalsRegister, Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop))); - } + 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) { @@ -158,9 +132,9 @@ void InstructionSelection::run(int functionIndex) for (IR::Stmt *s : _block->statements()) { if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { - _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); - Assembler::Address lineAddr(Assembler::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber)); - _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr); + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); + Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber)); + _as->store32(TrustedImm32(s->location.startLine), lineAddr); lastLine = s->location.startLine; } } @@ -181,165 +155,187 @@ void InstructionSelection::run(int functionIndex) qSwap(_removableJumps, removableJumps); } -QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() +template <typename JITAssembler> +QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection<JITAssembler>::backendCompileStep() { QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; result.adopt(compilationUnit.take()); return result; } -void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *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(result, callGlobalLookup, - Assembler::EngineRegister, - Assembler::TrustedImm32(index), + generateRuntimeCall(_as, result, callGlobalLookup, + JITTargetPlatform::EngineRegister, + TrustedImm32(index), baseAddressForCallData()); } else { - generateRuntimeCall(result, callActivationProperty, - Assembler::EngineRegister, - Assembler::StringToIndex(*func->id), + generateRuntimeCall(_as, result, callActivationProperty, + JITTargetPlatform::EngineRegister, + StringToIndex(*func->id), baseAddressForCallData()); } } -void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base, +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(result, typeofScopeObjectProperty, Assembler::EngineRegister, - Assembler::PointerToValue(base), - Assembler::TrustedImm32(propertyIndex)); + generateRuntimeCall(_as, result, typeofScopeObjectProperty, JITTargetPlatform::EngineRegister, + PointerToValue(base), + TrustedImm32(propertyIndex)); } else if (kind == IR::Member::MemberOfQmlContextObject) { - generateRuntimeCall(result, typeofContextObjectProperty, - Assembler::EngineRegister, Assembler::PointerToValue(base), - Assembler::TrustedImm32(propertyIndex)); + generateRuntimeCall(_as, result, typeofContextObjectProperty, + JITTargetPlatform::EngineRegister, PointerToValue(base), + TrustedImm32(propertyIndex)); } else { Q_UNREACHABLE(); } } -void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name, +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) { - generateRuntimeCall(result, typeofMember, Assembler::EngineRegister, - Assembler::PointerToValue(base), Assembler::StringToIndex(name)); + generateRuntimeCall(_as, result, typeofMember, JITTargetPlatform::EngineRegister, + PointerToValue(base), StringToIndex(name)); } -void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) { - generateRuntimeCall(result, typeofElement, - Assembler::EngineRegister, - Assembler::PointerToValue(base), Assembler::PointerToValue(index)); + generateRuntimeCall(_as, result, typeofElement, + JITTargetPlatform::EngineRegister, + PointerToValue(base), PointerToValue(index)); } -void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinTypeofName(const QString &name, IR::Expr *result) { - generateRuntimeCall(result, typeofName, Assembler::EngineRegister, - Assembler::StringToIndex(name)); + generateRuntimeCall(_as, result, typeofName, JITTargetPlatform::EngineRegister, + StringToIndex(name)); } -void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) { - generateRuntimeCall(result, typeofValue, Assembler::EngineRegister, - Assembler::PointerToValue(value)); + generateRuntimeCall(_as, result, typeofValue, JITTargetPlatform::EngineRegister, + PointerToValue(value)); } -void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) { - generateRuntimeCall(result, deleteMember, Assembler::EngineRegister, - Assembler::Reference(base), Assembler::StringToIndex(name)); + generateRuntimeCall(_as, result, deleteMember, JITTargetPlatform::EngineRegister, + Reference(base), StringToIndex(name)); } -void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) { - generateRuntimeCall(result, deleteElement, Assembler::EngineRegister, - Assembler::Reference(base), Assembler::PointerToValue(index)); + generateRuntimeCall(_as, result, deleteElement, JITTargetPlatform::EngineRegister, + Reference(base), PointerToValue(index)); } -void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &name, IR::Expr *result) { - generateRuntimeCall(result, deleteName, Assembler::EngineRegister, - Assembler::StringToIndex(name)); + generateRuntimeCall(_as, result, deleteName, JITTargetPlatform::EngineRegister, + StringToIndex(name)); } -void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result) { _as->storeValue(Primitive::fromBoolean(false), result); } -void InstructionSelection::callBuiltinThrow(IR::Expr *arg) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinThrow(IR::Expr *arg) { - generateRuntimeCall(Assembler::ReturnValueRegister, throwException, Assembler::EngineRegister, - Assembler::PointerToValue(arg)); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, throwException, JITTargetPlatform::EngineRegister, + PointerToValue(arg)); } -void InstructionSelection::callBuiltinReThrow() +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinReThrow() { _as->jumpToExceptionHandler(); } -void InstructionSelection::callBuiltinUnwindException(IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinUnwindException(IR::Expr *result) { - generateRuntimeCall(result, unwindException, Assembler::EngineRegister); + generateRuntimeCall(_as, result, unwindException, JITTargetPlatform::EngineRegister); } -void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinPushCatchScope(const QString &exceptionName) { - generateRuntimeCall(Assembler::Void, pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName)); + generateRuntimeCall(_as, JITAssembler::Void, pushCatchScope, JITTargetPlatform::EngineRegister, StringToIndex(exceptionName)); } -void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) { Q_ASSERT(arg); Q_ASSERT(result); - generateRuntimeCall(result, foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg)); + generateRuntimeCall(_as, result, foreachIterator, JITTargetPlatform::EngineRegister, PointerToValue(arg)); } -void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) { Q_ASSERT(arg); Q_ASSERT(result); - generateRuntimeCall(result, foreachNextPropertyName, Assembler::Reference(arg)); + generateRuntimeCall(_as, result, foreachNextPropertyName, Reference(arg)); } -void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinPushWithScope(IR::Expr *arg) { Q_ASSERT(arg); - generateRuntimeCall(Assembler::Void, pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister); + generateRuntimeCall(_as, JITAssembler::Void, pushWithScope, Reference(arg), JITTargetPlatform::EngineRegister); } -void InstructionSelection::callBuiltinPopScope() +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinPopScope() { - generateRuntimeCall(Assembler::Void, popScope, Assembler::EngineRegister); + generateRuntimeCall(_as, JITAssembler::Void, popScope, JITTargetPlatform::EngineRegister); } -void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDeclareVar(bool deletable, const QString &name) { - generateRuntimeCall(Assembler::Void, declareVar, Assembler::EngineRegister, - Assembler::TrustedImm32(deletable), Assembler::StringToIndex(name)); + generateRuntimeCall(_as, JITAssembler::Void, declareVar, JITTargetPlatform::EngineRegister, + TrustedImm32(deletable), StringToIndex(name)); } -void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) { Q_ASSERT(result); int length = prepareVariableArguments(args); - generateRuntimeCall(result, arrayLiteral, Assembler::EngineRegister, - baseAddressForCallArguments(), Assembler::TrustedImm32(length)); + generateRuntimeCall(_as, result, arrayLiteral, JITTargetPlatform::EngineRegister, + baseAddressForCallArguments(), TrustedImm32(length)); } -void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) { Q_ASSERT(result); @@ -415,81 +411,83 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int it = it->next; } - generateRuntimeCall(result, objectLiteral, Assembler::EngineRegister, - baseAddressForCallArguments(), Assembler::TrustedImm32(classId), - Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30))); + generateRuntimeCall(_as, result, objectLiteral, JITTargetPlatform::EngineRegister, + baseAddressForCallArguments(), TrustedImm32(classId), + TrustedImm32(arrayValueCount), TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30))); } -void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinSetupArgumentObject(IR::Expr *result) { - generateRuntimeCall(result, setupArgumentsObject, Assembler::EngineRegister); + generateRuntimeCall(_as, result, setupArgumentsObject, JITTargetPlatform::EngineRegister); } -void InstructionSelection::callBuiltinConvertThisToObject() +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callBuiltinConvertThisToObject() { - generateRuntimeCall(Assembler::Void, convertThisToObject, Assembler::EngineRegister); + generateRuntimeCall(_as, JITAssembler::Void, convertThisToObject, JITTargetPlatform::EngineRegister); } -void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) +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(result, callValue, Assembler::EngineRegister, - Assembler::PointerToValue(value), + generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister, + PointerToValue(value), baseAddressForCallData()); else - generateRuntimeCall(result, callValue, Assembler::EngineRegister, - Assembler::Reference(value), + generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister, + Reference(value), baseAddressForCallData()); } -void InstructionSelection::loadThisObject(IR::Expr *temp) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp) { - _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); - _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister); -#if defined(VALUE_FITS_IN_REGISTER) - _as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)), - Assembler::ReturnValueRegister); - _as->storeReturnValue(temp); -#else - _as->copyValue(temp, Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject))); -#endif + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); + _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); + _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); } -void InstructionSelection::loadQmlContext(IR::Expr *temp) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadQmlContext(IR::Expr *temp) { - generateRuntimeCall(temp, getQmlContext, Assembler::EngineRegister); + generateRuntimeCall(_as, temp, getQmlContext, JITTargetPlatform::EngineRegister); } -void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadQmlImportedScripts(IR::Expr *temp) { - generateRuntimeCall(temp, getQmlImportedScripts, Assembler::EngineRegister); + generateRuntimeCall(_as, temp, getQmlImportedScripts, JITTargetPlatform::EngineRegister); } -void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadQmlSingleton(const QString &name, IR::Expr *temp) { - generateRuntimeCall(temp, getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name)); + generateRuntimeCall(_as, temp, getQmlSingleton, JITTargetPlatform::EngineRegister, StringToIndex(name)); } -void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target) +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, (Assembler::FPRegisterID) targetTemp->index); + _as->toDoubleRegister(sourceConst, (FPRegisterID) targetTemp->index); } else if (targetTemp->type == IR::SInt32Type) { Q_ASSERT(sourceConst->type == IR::SInt32Type); - _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); + _as->toInt32Register(sourceConst, (RegisterID) targetTemp->index); } else if (targetTemp->type == IR::UInt32Type) { Q_ASSERT(sourceConst->type == IR::UInt32Type); - _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); + _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()), - (Assembler::RegisterID) targetTemp->index); + _as->move(TrustedImm32(convertToValue(sourceConst).int_32()), + (RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); } @@ -500,147 +498,155 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target) _as->storeValue(convertToValue(sourceConst), target); } -void InstructionSelection::loadString(const QString &str, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr *target) { - Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str); - _as->loadPtr(srcAddr, Assembler::ReturnValueRegister); - Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target); -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - _as->store64(Assembler::ReturnValueRegister, destAddr); -#else - _as->store32(Assembler::ReturnValueRegister, destAddr); - destAddr.offset += 4; - _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr); -#endif + Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str); + _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister); + Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target); + JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr); } -void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) { int id = registerRegExp(sourceRegexp); - generateRuntimeCall(target, regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id)); + generateRuntimeCall(_as, target, regexpLiteral, JITTargetPlatform::EngineRegister, TrustedImm32(id)); } -void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target) +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, qOffsetOf(QV4::Lookup, globalGetter), Assembler::EngineRegister, Assembler::Void); + generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void); return; } - generateRuntimeCall(target, getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id)); + generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id)); } -void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::setActivationProperty(IR::Expr *source, const QString &targetName) { // ### should use a lookup call here - generateRuntimeCall(Assembler::Void, setActivationProperty, - Assembler::EngineRegister, Assembler::StringToIndex(targetName), Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setActivationProperty, + JITTargetPlatform::EngineRegister, StringToIndex(targetName), PointerToValue(source)); } -void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::initClosure(IR::Closure *closure, IR::Expr *target) { int id = closure->value; - generateRuntimeCall(target, closure, Assembler::EngineRegister, Assembler::TrustedImm32(id)); + generateRuntimeCall(_as, target, closure, JITTargetPlatform::EngineRegister, TrustedImm32(id)); } -void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target) +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, qOffsetOf(QV4::Lookup, getter), Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::Void); + generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void); } else { - generateRuntimeCall(target, getProperty, Assembler::EngineRegister, - Assembler::PointerToValue(base), Assembler::StringToIndex(name)); + generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister, + PointerToValue(base), StringToIndex(name)); } } -void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target) +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(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired)); + generateRuntimeCall(_as, target, getQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired)); else if (kind == IR::Member::MemberOfQmlContextObject) - generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired)); + generateRuntimeCall(_as, target, getQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired)); else if (kind == IR::Member::MemberOfIdObjectsArray) - generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + generateRuntimeCall(_as, target, getQmlIdObject, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index)); else Q_ASSERT(false); } -void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) +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(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex)); + generateRuntimeCall(_as, target, getQmlAttachedProperty, JITTargetPlatform::EngineRegister, TrustedImm32(attachedPropertiesId), TrustedImm32(propertyIndex)); else if (isSingleton) - generateRuntimeCall(target, getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex), - Assembler::TrustedImm32(captureRequired)); + generateRuntimeCall(_as, target, getQmlSingletonQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex), + TrustedImm32(captureRequired)); else - generateRuntimeCall(target, getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex), - Assembler::TrustedImm32(captureRequired)); + generateRuntimeCall(_as, target, getQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex), + TrustedImm32(captureRequired)); } -void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase, +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) { if (useFastLookups) { uint index = registerSetterLookup(targetName); - generateLookupCall(Assembler::Void, index, qOffsetOf(QV4::Lookup, setter), - Assembler::EngineRegister, - Assembler::PointerToValue(targetBase), - Assembler::PointerToValue(source)); + generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter), + JITTargetPlatform::EngineRegister, + PointerToValue(targetBase), + PointerToValue(source)); } else { - generateRuntimeCall(Assembler::Void, setProperty, Assembler::EngineRegister, - Assembler::PointerToValue(targetBase), Assembler::StringToIndex(targetName), - Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setProperty, JITTargetPlatform::EngineRegister, + PointerToValue(targetBase), StringToIndex(targetName), + PointerToValue(source)); } } -void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) +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(Assembler::Void, setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), - Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase), + TrustedImm32(propertyIndex), PointerToValue(source)); else if (kind == IR::Member::MemberOfQmlContextObject) - generateRuntimeCall(Assembler::Void, setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), - Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase), + TrustedImm32(propertyIndex), PointerToValue(source)); else Q_ASSERT(false); } -void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) { - generateRuntimeCall(Assembler::Void, setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), - Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase), + TrustedImm32(propertyIndex), PointerToValue(source)); } -void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) { if (useFastLookups) { uint lookup = registerIndexedGetterLookup(); generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter), - Assembler::PointerToValue(base), - Assembler::PointerToValue(index)); + PointerToValue(base), + PointerToValue(index)); return; } - generateRuntimeCall(target, getElement, Assembler::EngineRegister, - Assembler::PointerToValue(base), Assembler::PointerToValue(index)); + generateRuntimeCall(_as, target, getElement, JITTargetPlatform::EngineRegister, + PointerToValue(base), PointerToValue(index)); } -void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) { if (useFastLookups) { uint lookup = registerIndexedSetterLookup(); - generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter), - Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex), - Assembler::PointerToValue(source)); + generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter), + PointerToValue(targetBase), PointerToValue(targetIndex), + PointerToValue(source)); return; } - generateRuntimeCall(Assembler::Void, setElement, Assembler::EngineRegister, - Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex), - Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITAssembler::Void, setElement, JITTargetPlatform::EngineRegister, + PointerToValue(targetBase), PointerToValue(targetIndex), + PointerToValue(source)); } -void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *target) { IR::Temp *sourceTemp = source->asTemp(); IR::Temp *targetTemp = target->asTemp(); @@ -655,25 +661,25 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) { if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { if (sourceTemp->type == IR::DoubleType) - _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index, - (Assembler::FPRegisterID) targetTemp->index); + _as->moveDouble((FPRegisterID) sourceTemp->index, + (FPRegisterID) targetTemp->index); else - _as->move((Assembler::RegisterID) sourceTemp->index, - (Assembler::RegisterID) targetTemp->index); + _as->move((RegisterID) sourceTemp->index, + (RegisterID) targetTemp->index); return; } else { switch (sourceTemp->type) { case IR::DoubleType: - _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target); + _as->storeDouble((FPRegisterID) sourceTemp->index, target); break; case IR::SInt32Type: - _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target); + _as->storeInt32((RegisterID) sourceTemp->index, target); break; case IR::UInt32Type: - _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target); + _as->storeUInt32((RegisterID) sourceTemp->index, target); break; case IR::BoolType: - _as->storeBool((Assembler::RegisterID) sourceTemp->index, target); + _as->storeBool((RegisterID) sourceTemp->index, target); break; default: Q_ASSERT(!"Unreachable"); @@ -685,19 +691,19 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) switch (targetTemp->type) { case IR::DoubleType: Q_ASSERT(source->type == IR::DoubleType); - _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index); + _as->toDoubleRegister(source, (FPRegisterID) targetTemp->index); return; case IR::BoolType: Q_ASSERT(source->type == IR::BoolType); - _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index); + _as->toInt32Register(source, (RegisterID) targetTemp->index); return; case IR::SInt32Type: Q_ASSERT(source->type == IR::SInt32Type); - _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index); + _as->toInt32Register(source, (RegisterID) targetTemp->index); return; case IR::UInt32Type: Q_ASSERT(source->type == IR::UInt32Type); - _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index); + _as->toUInt32Register(source, (RegisterID) targetTemp->index); return; default: Q_ASSERT(!"Unreachable"); @@ -706,10 +712,11 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) } // The target is not a physical register, nor is the source. So we can do a memory-to-memory copy: - _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister); + _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister); } -void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *target) { IR::Temp *sourceTemp = source->asTemp(); IR::Temp *targetTemp = target->asTemp(); @@ -719,26 +726,27 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) Q_ASSERT(sourceTemp->type == targetTemp->type); if (sourceTemp->type == IR::DoubleType) { - _as->moveDouble((Assembler::FPRegisterID) targetTemp->index, Assembler::FPGpr0); - _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index, - (Assembler::FPRegisterID) targetTemp->index); - _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) sourceTemp->index); + _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((Assembler::RegisterID) sourceTemp->index, - (Assembler::RegisterID) targetTemp->index); + _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. - Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source); - Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target); + Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target); // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling - _as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0); - _as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1); - _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr1, sAddr); - _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr0, tAddr); + auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as); + platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0); + platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1); + platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr); + platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr); return; } } @@ -749,18 +757,18 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) Q_ASSERT(memExpr); Q_ASSERT(regTemp); - Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr); + Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr); if (regTemp->type == IR::DoubleType) { - _as->loadDouble(addr, Assembler::FPGpr0); - _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr); - _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index); + _as->loadDouble(addr, JITTargetPlatform::FPGpr0); + _as->storeDouble((FPRegisterID) regTemp->index, addr); + _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index); } else if (regTemp->type == IR::UInt32Type) { - _as->toUInt32Register(addr, Assembler::ScratchRegister); - _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr); - _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index); + _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister); + _as->storeUInt32((RegisterID) regTemp->index, addr); + _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } else { - _as->load32(addr, Assembler::ScratchRegister); - _as->store32((Assembler::RegisterID) regTemp->index, addr); + _as->load32(addr, JITTargetPlatform::ScratchRegister); + _as->store32((RegisterID) regTemp->index, addr); if (regTemp->type != memExpr->type) { addr.offset += 4; quint32 tag; @@ -775,55 +783,59 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) tag = 31337; // bogus value Q_UNREACHABLE(); } - _as->store32(Assembler::TrustedImm32(tag), addr); + _as->store32(TrustedImm32(tag), addr); } - _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index); + _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } } #define setOp(op, opName, operation) \ do { \ - op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ + op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \ } while (0) #define setOpContext(op, opName, operation) \ do { \ - opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ + opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \ } while (0) -void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) { - QV4::JIT::Unop unop(_as, oper); + QV4::JIT::Unop<JITAssembler> unop(_as, oper); unop.generate(source, target); } -void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { - QV4::JIT::Binop binop(_as, oper); + QV4::JIT::Binop<JITAssembler> binop(_as, oper); binop.generate(leftSource, rightSource, target); } -void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) +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(result, callQmlScopeObjectProperty, - Assembler::EngineRegister, - Assembler::TrustedImm32(propertyIndex), + generateRuntimeCall(_as, result, callQmlScopeObjectProperty, + JITTargetPlatform::EngineRegister, + TrustedImm32(propertyIndex), baseAddressForCallData()); else if (kind == IR::Member::MemberOfQmlContextObject) - generateRuntimeCall(result, callQmlContextObjectProperty, - Assembler::EngineRegister, - Assembler::TrustedImm32(propertyIndex), + generateRuntimeCall(_as, result, callQmlContextObjectProperty, + JITTargetPlatform::EngineRegister, + TrustedImm32(propertyIndex), baseAddressForCallData()); else Q_ASSERT(false); } -void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { Q_ASSERT(base != 0); @@ -832,29 +844,31 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR: if (useFastLookups) { uint index = registerGetterLookup(name); - generateRuntimeCall(result, callPropertyLookup, - Assembler::EngineRegister, - Assembler::TrustedImm32(index), + generateRuntimeCall(_as, result, callPropertyLookup, + JITTargetPlatform::EngineRegister, + TrustedImm32(index), baseAddressForCallData()); } else { - generateRuntimeCall(result, callProperty, Assembler::EngineRegister, - Assembler::StringToIndex(name), + generateRuntimeCall(_as, result, callProperty, JITTargetPlatform::EngineRegister, + StringToIndex(name), baseAddressForCallData()); } } -void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, +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(result, callElement, Assembler::EngineRegister, - Assembler::PointerToValue(index), + generateRuntimeCall(_as, result, callElement, JITTargetPlatform::EngineRegister, + PointerToValue(index), baseAddressForCallData()); } -void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertType(IR::Expr *source, IR::Expr *target) { switch (target->type) { case IR::DoubleType: @@ -875,7 +889,8 @@ void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target) } } -void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertTypeSlowPath(IR::Expr *source, IR::Expr *target) { Q_ASSERT(target->type != IR::BoolType); @@ -885,7 +900,8 @@ void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *targe copyValue(source, target); } -void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::SInt32Type: @@ -897,51 +913,37 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe convertUIntToDouble(source, target); break; case IR::UndefinedType: - _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0); - _as->storeDouble(Assembler::FPGpr0, target); + _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0); + _as->storeDouble(JITTargetPlatform::FPGpr0, target); break; case IR::StringType: case IR::VarType: { // load the tag: - Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source); + Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ScratchRegister); + _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); // check if it's an int32: - Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); + Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, + TrustedImm32(Value::Integer_Type_Internal)); convertIntToDouble(source, target); - Assembler::Jump intDone = _as->jump(); + Jump intDone = _as->jump(); // not an int, check if it's NOT a double: isNoInt.link(_as); -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister); - Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(0)); -#else - _as->and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::NotDouble_Mask)); -#endif + Jump isDbl = _as->generateIsDoubleCheck(JITTargetPlatform::ScratchRegister); - generateRuntimeCall(target, toDouble, Assembler::PointerToValue(source)); - Assembler::Jump noDoubleDone = _as->jump(); + generateRuntimeCall(_as, target, toDouble, PointerToValue(source)); + Jump noDoubleDone = _as->jump(); // it is a double: isDbl.link(_as); - Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source); + Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { -#if Q_PROCESSOR_WORDSIZE == 8 - _as->load64(addr2, Assembler::ScratchRegister); - _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target)); -#else - _as->loadDouble(addr2, Assembler::FPGpr0); - _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target)); -#endif + _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister); } else { - _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index); + _as->loadDouble(addr2, (FPRegisterID) targetTemp->index); } noDoubleDone.link(_as); @@ -953,7 +955,8 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe } } -void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR::Expr *target) { IR::Temp *sourceTemp = source->asTemp(); switch (source->type) { @@ -965,16 +968,16 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target) // 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. - Assembler::FPRegisterID reg; + FPRegisterID reg; if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) - reg = (Assembler::FPRegisterID) sourceTemp->index; + reg = (FPRegisterID) sourceTemp->index; else - reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1); - Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0); + reg = _as->toDoubleRegister(source, (FPRegisterID) 1); + Jump nonZero = _as->branchDoubleNonZero(reg, JITTargetPlatform::FPGpr0); // it's 0, so false: _as->storeBool(false, target); - Assembler::Jump done = _as->jump(); + Jump done = _as->jump(); // it's non-zero, so true: nonZero.link(_as); @@ -988,283 +991,220 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target) _as->storeBool(false, target); break; case IR::StringType: - generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean, - Assembler::PointerToValue(source)); - _as->storeBool(Assembler::ReturnValueRegister, target); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean, + PointerToValue(source)); + _as->storeBool(JITTargetPlatform::ReturnValueRegister, target); case IR::VarType: default: - Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); - Assembler::Pointer tagAddr = addr; + Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tagAddr = addr; tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ReturnValueRegister); + _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister); // checkif it's a bool: - Assembler::Jump notBool = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, - Assembler::TrustedImm32(Value::Boolean_Type_Internal)); - _as->load32(addr, Assembler::ReturnValueRegister); - Assembler::Jump boolDone = _as->jump(); + Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, + TrustedImm32(Value::Boolean_Type_Internal)); + _as->load32(addr, JITTargetPlatform::ReturnValueRegister); + Jump boolDone = _as->jump(); // check if it's an int32: notBool.link(_as); - Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); - _as->load32(addr, Assembler::ReturnValueRegister); - Assembler::Jump isZero = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, - Assembler::TrustedImm32(0)); - _as->move(Assembler::TrustedImm32(1), Assembler::ReturnValueRegister); - Assembler::Jump intDone = _as->jump(); + Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, + TrustedImm32(Value::Integer_Type_Internal)); + _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(Assembler::ReturnValueRegister, toBoolean, - Assembler::PointerToValue(source)); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean, + PointerToValue(source)); isZero.link(_as); intDone.link(_as); boolDone.link(_as); - _as->storeBool(Assembler::ReturnValueRegister, target); + _as->storeBool(JITTargetPlatform::ReturnValueRegister, target); break; } } -void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::VarType: { - -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); - _as->load64(addr, Assembler::ScratchRegister); - _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - - // check if it's integer convertible - _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister); - Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3)); - - // nope, not integer convertible, so check for a double: - _as->urshift64(Assembler::TrustedImm32( - QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift), - Assembler::ScratchRegister); - Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); - - // it's a double - _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); - _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0); - Assembler::Jump success = - _as->branchTruncateDoubleToInt32(Assembler::FPGpr0, Assembler::ReturnValueRegister, - Assembler::BranchIfTruncateSuccessful); - - // not an int: - fallback.link(_as); - generateRuntimeCall(Assembler::ReturnValueRegister, toInt, - _as->loadAddress(Assembler::ScratchRegister, source)); - - isIntConvertible.link(_as); - success.link(_as); - IR::Temp *targetTemp = target->asTemp(); - if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { - Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target); - _as->store32(Assembler::ReturnValueRegister, targetAddr); - targetAddr.offset += 4; - _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr); - } else { - _as->storeInt32(Assembler::ReturnValueRegister, target); - } -#else - // load the tag: - Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); - Assembler::Pointer tagAddr = addr; - tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ReturnValueRegister); - - // check if it's an int32: - Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); - IR::Temp *targetTemp = target->asTemp(); - if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { - _as->load32(addr, Assembler::ReturnValueRegister); - Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target); - _as->store32(Assembler::ReturnValueRegister, targetAddr); - targetAddr.offset += 4; - _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr); - } else { - _as->load32(addr, (Assembler::RegisterID) targetTemp->index); - } - Assembler::Jump intDone = _as->jump(); - - // not an int: - fallback.link(_as); - generateRuntimeCall(Assembler::ReturnValueRegister, toInt, - _as->loadAddress(Assembler::ScratchRegister, source)); - _as->storeInt32(Assembler::ReturnValueRegister, target); - - intDone.link(_as); -#endif - + JITAssembler::RegisterSizeDependentOps::convertVarToSInt32(_as, source, target); } break; case IR::DoubleType: { - Assembler::Jump success = + Jump success = _as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source), - Assembler::ReturnValueRegister, - Assembler::BranchIfTruncateSuccessful); - generateRuntimeCall(Assembler::ReturnValueRegister, doubleToInt, - Assembler::PointerToValue(source)); + JITTargetPlatform::ReturnValueRegister, + BranchTruncateType::BranchIfTruncateSuccessful); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToInt, + PointerToValue(source)); success.link(_as); - _as->storeInt32(Assembler::ReturnValueRegister, target); + _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); } break; case IR::UInt32Type: - _as->storeInt32(_as->toUInt32Register(source, Assembler::ReturnValueRegister), target); + _as->storeInt32(_as->toUInt32Register(source, JITTargetPlatform::ReturnValueRegister), target); break; case IR::NullType: case IR::UndefinedType: - _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister); - _as->storeInt32(Assembler::ReturnValueRegister, target); + _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister); + _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); break; case IR::BoolType: - _as->storeInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target); + _as->storeInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target); break; case IR::StringType: default: - generateRuntimeCall(Assembler::ReturnValueRegister, toInt, - _as->loadAddress(Assembler::ScratchRegister, source)); - _as->storeInt32(Assembler::ReturnValueRegister, target); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt, + _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); break; } // switch (source->type) } -void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::VarType: { // load the tag: - Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source); + Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; - _as->load32(tagAddr, Assembler::ScratchRegister); + _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); // check if it's an int32: - Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); - Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); - _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target); - Assembler::Jump intDone = _as->jump(); + Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, + TrustedImm32(Value::Integer_Type_Internal)); + Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target); + Jump intDone = _as->jump(); // not an int: isNoInt.link(_as); - generateRuntimeCall(Assembler::ReturnValueRegister, toUInt, - _as->loadAddress(Assembler::ScratchRegister, source)); - _as->storeInt32(Assembler::ReturnValueRegister, target); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt, + _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); intDone.link(_as); } break; case IR::DoubleType: { - Assembler::FPRegisterID reg = _as->toDoubleRegister(source); - Assembler::Jump success = - _as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister, - Assembler::BranchIfTruncateSuccessful); - generateRuntimeCall(Assembler::ReturnValueRegister, doubleToUInt, - Assembler::PointerToValue(source)); + 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(Assembler::ReturnValueRegister, target); + _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target); } break; case IR::NullType: case IR::UndefinedType: - _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister); - _as->storeUInt32(Assembler::ReturnValueRegister, target); + _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister); + _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target); break; case IR::StringType: - generateRuntimeCall(Assembler::ReturnValueRegister, toUInt, - Assembler::PointerToValue(source)); - _as->storeUInt32(Assembler::ReturnValueRegister, target); + generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt, + PointerToValue(source)); + _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target); break; case IR::SInt32Type: case IR::BoolType: - _as->storeUInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target); + _as->storeUInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target); break; default: break; } // switch (source->type) } -void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) +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(result, constructGlobalLookup, - Assembler::EngineRegister, - Assembler::TrustedImm32(index), baseAddressForCallData()); + generateRuntimeCall(_as, result, constructGlobalLookup, + JITTargetPlatform::EngineRegister, + TrustedImm32(index), baseAddressForCallData()); return; } - generateRuntimeCall(result, constructActivationProperty, - Assembler::EngineRegister, - Assembler::StringToIndex(*func->id), + generateRuntimeCall(_as, result, constructActivationProperty, + JITTargetPlatform::EngineRegister, + StringToIndex(*func->id), baseAddressForCallData()); } -void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) +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(result, constructPropertyLookup, - Assembler::EngineRegister, - Assembler::TrustedImm32(index), + generateRuntimeCall(_as, result, constructPropertyLookup, + JITTargetPlatform::EngineRegister, + TrustedImm32(index), baseAddressForCallData()); return; } - generateRuntimeCall(result, constructProperty, Assembler::EngineRegister, - Assembler::StringToIndex(name), + generateRuntimeCall(_as, result, constructProperty, JITTargetPlatform::EngineRegister, + StringToIndex(name), baseAddressForCallData()); } -void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { Q_ASSERT(value != 0); prepareCallData(args, 0); - generateRuntimeCall(result, constructValue, - Assembler::EngineRegister, - Assembler::Reference(value), + generateRuntimeCall(_as, result, constructValue, + JITTargetPlatform::EngineRegister, + Reference(value), baseAddressForCallData()); } -void InstructionSelection::visitJump(IR::Jump *s) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::visitJump(IR::Jump *s) { if (!_removableJumps.at(_block->index())) _as->jumpToBlock(_block, s->target); } -void InstructionSelection::visitCJump(IR::CJump *s) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s) { IR::Temp *t = s->cond->asTemp(); if (t || s->cond->asArgLocal()) { - Assembler::RegisterID reg; + RegisterID reg; if (t && t->kind == IR::Temp::PhysicalRegister) { Q_ASSERT(t->type == IR::BoolType); - reg = (Assembler::RegisterID) t->index; + reg = (RegisterID) t->index; } else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) { - reg = Assembler::ReturnValueRegister; + reg = JITTargetPlatform::ReturnValueRegister; _as->toInt32Register(t, reg); } else { - Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond); + Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); - Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal)); + Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal)); Address data = temp; data.offset += QV4::Value::valueOffset(); - _as->load32(data, Assembler::ReturnValueRegister); - Assembler::Jump testBoolean = _as->jump(); + _as->load32(data, JITTargetPlatform::ReturnValueRegister); + Jump testBoolean = _as->jump(); booleanConversion.link(_as); - reg = Assembler::ReturnValueRegister; - generateRuntimeCall(reg, toBoolean, Assembler::Reference(s->cond)); + reg = JITTargetPlatform::ReturnValueRegister; + generateRuntimeCall(_as, reg, toBoolean, Reference(s->cond)); testBoolean.link(_as); } @@ -1274,9 +1214,9 @@ void InstructionSelection::visitCJump(IR::CJump *s) } else if (IR::Const *c = s->cond->asConst()) { // TODO: SSA optimization for constant condition evaluation should remove this. // See also visitCJump() in RegAllocInfo. - generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean, - Assembler::PointerToValue(c)); - _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse); + 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 @@ -1296,8 +1236,8 @@ void InstructionSelection::visitCJump(IR::CJump *s) return; } - RuntimeCall op; - RuntimeCall opContext; + typename JITAssembler::RuntimeCall op; + typename JITAssembler::RuntimeCall opContext; const char *opName = 0; bool needsExceptionCheck; switch (b->op) { @@ -1321,165 +1261,30 @@ void InstructionSelection::visitCJump(IR::CJump *s) // elimination (which isn't there either) would remove the whole else block. if (opContext.isValid()) _as->generateFunctionCallImp(needsExceptionCheck, - Assembler::ReturnValueRegister, opName, opContext, - Assembler::EngineRegister, - Assembler::PointerToValue(b->left), - Assembler::PointerToValue(b->right)); + JITTargetPlatform::ReturnValueRegister, opName, opContext, + JITTargetPlatform::EngineRegister, + PointerToValue(b->left), + PointerToValue(b->right)); else _as->generateFunctionCallImp(needsExceptionCheck, - Assembler::ReturnValueRegister, opName, op, - Assembler::PointerToValue(b->left), - Assembler::PointerToValue(b->right)); + JITTargetPlatform::ReturnValueRegister, opName, op, + PointerToValue(b->left), + PointerToValue(b->right)); - _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse); + _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse); return; } Q_UNREACHABLE(); } -void InstructionSelection::visitRet(IR::Ret *s) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::visitRet(IR::Ret *s) { - 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()) { -#if CPU(X86) || CPU(ARM) || CPU(MIPS) - -# if CPU(X86) - Assembler::RegisterID lowReg = JSC::X86Registers::eax; - Assembler::RegisterID highReg = JSC::X86Registers::edx; -# elif CPU(MIPS) - Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0; - Assembler::RegisterID highReg = JSC::MIPSRegisters::v1; -# else // CPU(ARM) - Assembler::RegisterID lowReg = JSC::ARMRegisters::r0; - Assembler::RegisterID highReg = JSC::ARMRegisters::r1; -# endif - - if (t->kind == IR::Temp::PhysicalRegister) { - switch (t->type) { - case IR::DoubleType: - _as->moveDoubleToInts((Assembler::FPRegisterID) t->index, lowReg, highReg); - break; - case IR::UInt32Type: { - Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index; - Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0)); - _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister); - _as->moveDoubleToInts(Assembler::FPGpr0, lowReg, highReg); - Assembler::Jump done = _as->jump(); - intRange.link(_as); - _as->move(srcReg, lowReg); - _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); - done.link(_as); - } break; - case IR::SInt32Type: - _as->move((Assembler::RegisterID) t->index, lowReg); - _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); - break; - case IR::BoolType: - _as->move((Assembler::RegisterID) t->index, lowReg); - _as->move(Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg); - break; - default: - Q_UNREACHABLE(); - } - } else { - Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t); - _as->load32(addr, lowReg); - addr.offset += 4; - _as->load32(addr, highReg); - } -#else - if (t->kind == IR::Temp::PhysicalRegister) { - if (t->type == IR::DoubleType) { - _as->moveDoubleTo64((Assembler::FPRegisterID) t->index, - Assembler::ReturnValueRegister); - _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), - Assembler::ScratchRegister); - _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - } else if (t->type == IR::UInt32Type) { - Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index; - Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0)); - _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister); - _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister); - _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); - _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - Assembler::Jump done = _as->jump(); - intRange.link(_as); - _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister); - quint64 tag = QV4::Value::Integer_Type_Internal; - _as->or64(Assembler::TrustedImm64(tag << 32), - Assembler::ReturnValueRegister); - done.link(_as); - } else { - _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister); - quint64 tag; - switch (t->type) { - case IR::SInt32Type: - tag = QV4::Value::Integer_Type_Internal; - break; - case IR::BoolType: - tag = QV4::Value::Boolean_Type_Internal; - break; - default: - tag = 31337; // bogus value - Q_UNREACHABLE(); - } - _as->or64(Assembler::TrustedImm64(tag << 32), - Assembler::ReturnValueRegister); - } - } else { - _as->copyValue(Assembler::ReturnValueRegister, t); - } -#endif - } else if (IR::Const *c = s->expr->asConst()) { - QV4::Primitive retVal = convertToValue(c); -#if CPU(X86) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx); -#elif CPU(ARM) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1); -#elif CPU(MIPS) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1); -#else - _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); -#endif - } else { - Q_UNREACHABLE(); - Q_UNUSED(s); - } - - Assembler::Label leaveStackFrame = _as->label(); - - const int locals = _as->stackLayout().calculateJSStackFrameSize(); - _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister); - _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); - _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister); - _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop))); - - _as->leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); - _as->ret(); - - _as->exceptionReturnLabel = _as->label(); - QV4::Primitive retVal = Primitive::undefinedValue(); -#if CPU(X86) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx); -#elif CPU(ARM) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1); -#elif CPU(MIPS) - _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0); - _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1); -#else - _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); -#endif - _as->jump(leaveStackFrame); + _as->returnFromFunction(s, regularRegistersToSave, fpRegistersToSave); } -int InstructionSelection::prepareVariableArguments(IR::ExprList* args) +template <typename JITAssembler> +int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* args) { int argc = 0; for (IR::ExprList *it = args; it; it = it->next) { @@ -1492,7 +1297,7 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args) Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); else _as->copyValue(dst, arg); } @@ -1500,7 +1305,8 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args) return argc; } -int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObject) +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) { @@ -1508,9 +1314,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje } Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag)); - _as->store32(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), p); + _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p); p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc)); - _as->store32(Assembler::TrustedImm32(argc), p); + _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject)); if (!thisObject) _as->storeValue(QV4::Primitive::undefinedValue(), p); @@ -1523,25 +1329,24 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); else _as->copyValue(dst, arg); } return argc; } -void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used) +template <typename JITAssembler> +void InstructionSelection<JITAssembler>::calculateRegistersToSave(const RegisterInformation &used) { regularRegistersToSave.clear(); fpRegistersToSave.clear(); - for (const RegisterInfo &ri : Assembler::getRegisterInfo()) { -#if defined(RESTORE_EBX_ON_CALL) - if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { + for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) { + if (JITTargetPlatform::gotRegister != -1 && ri.isRegularRegister() && ri.reg<RegisterID>() == JITTargetPlatform::gotRegister) { regularRegistersToSave.append(ri); continue; } -#endif // RESTORE_EBX_ON_CALL if (ri.isCallerSaved()) continue; if (ri.isRegularRegister()) { @@ -1564,35 +1369,38 @@ bool operator==(const Primitive &v1, const Primitive &v2) } // QV4 namespace QT_END_NAMESPACE -bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right, +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) { - Assembler::Jump target = _as->branchDouble(true, op, left, right); + Jump target = _as->branchDouble(true, op, left, right); _as->addPatch(iffalse, target); } else { - Assembler::Jump target = _as->branchDouble(false, op, left, right); + Jump target = _as->branchDouble(false, op, left, right); _as->addPatch(iftrue, target); _as->jumpToBlock(_block, iffalse); } return true; } -bool InstructionSelection::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right, +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) { - Assembler::Jump target = _as->branchInt32(true, op, left, right); + Jump target = _as->branchInt32(true, op, left, right); _as->addPatch(iffalse, target); } else { - Assembler::Jump target = _as->branchInt32(false, op, left, right); + Jump target = _as->branchInt32(false, op, left, right); _as->addPatch(iftrue, target); _as->jumpToBlock(_block, iffalse); } return true; } -void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock, +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); @@ -1607,15 +1415,16 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr IR::Expr *left = binop->left; IR::Expr *right = binop->right; - generateRuntimeCall(Assembler::ReturnValueRegister, compareStrictEqual, - Assembler::PointerToValue(left), Assembler::PointerToValue(right)); - _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal, - Assembler::ReturnValueRegister, Assembler::TrustedImm32(0), + 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. -bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, +template <typename JITAssembler> +bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { @@ -1640,19 +1449,20 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, return true; } - Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; - const Assembler::RegisterID tagReg = Assembler::ScratchRegister; + const RegisterID tagReg = JITTargetPlatform::ScratchRegister; _as->load32(tagAddr, tagReg); - Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal - : Assembler::NotEqual; - const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal); + RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal + : RelationalCondition::NotEqual; + const TrustedImm32 tag(QV4::Value::Null_Type_Internal); _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); return true; } -bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop, +template <typename JITAssembler> +bool InstructionSelection<JITAssembler>::visitCJumpStrictUndefined(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { @@ -1677,28 +1487,15 @@ bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop, return true; } - Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal - : Assembler::NotEqual; - const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister; -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc); - _as->load64(addr, tagReg); - const Assembler::TrustedImm64 tag(0); -#else // !QV4_USE_64_BIT_VALUE_ENCODING - Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); - _as->load32(tagAddr, tagReg); - Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0)); - _as->addPatch(falseBlock, j); - - tagAddr.offset += 4; - _as->load32(tagAddr, tagReg); - const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal); -#endif - _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); + 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; } -bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, +template <typename JITAssembler> +bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { IR::Expr *boolSrc = 0, *otherSrc = 0; @@ -1712,13 +1509,20 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock // 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; + } - Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal - : Assembler::NotEqual; + RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal + : RelationalCondition::NotEqual; if (otherSrc->type == IR::BoolType) { // both are boolean - Assembler::RegisterID one = _as->toBoolRegister(boolSrc, Assembler::ReturnValueRegister); - Assembler::RegisterID two = _as->toBoolRegister(otherSrc, Assembler::ScratchRegister); + RegisterID one = _as->toBoolRegister(boolSrc, JITTargetPlatform::ReturnValueRegister); + RegisterID two = _as->toBoolRegister(otherSrc, JITTargetPlatform::ScratchRegister); _as->generateCJumpOnCompare(cond, one, two, _block, trueBlock, falseBlock); return true; } @@ -1728,13 +1532,13 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock return true; } - Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc); + Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc); otherAddr.offset += 4; // tag address // check if the tag of the var operand is indicates 'boolean' - _as->load32(otherAddr, Assembler::ScratchRegister); - Assembler::Jump noBool = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal)); + _as->load32(otherAddr, JITTargetPlatform::ScratchRegister); + Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, + TrustedImm32(QV4::Value::Boolean_Type_Internal)); if (binop->op == IR::OpStrictEqual) _as->addPatch(falseBlock, noBool); else @@ -1742,14 +1546,15 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock // ok, both are boolean, so let's load them and compare them. otherAddr.offset -= 4; // int_32 address - _as->load32(otherAddr, Assembler::ReturnValueRegister); - Assembler::RegisterID boolReg = _as->toBoolRegister(boolSrc, Assembler::ScratchRegister); - _as->generateCJumpOnCompare(cond, boolReg, Assembler::ReturnValueRegister, _block, trueBlock, + _as->load32(otherAddr, JITTargetPlatform::ReturnValueRegister); + RegisterID boolReg = _as->toBoolRegister(boolSrc, JITTargetPlatform::ScratchRegister); + _as->generateCJumpOnCompare(cond, boolReg, JITTargetPlatform::ReturnValueRegister, _block, trueBlock, falseBlock); return true; } -bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, +template <typename JITAssembler> +bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { @@ -1776,18 +1581,18 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin return true; } - Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; - const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister; + const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister; _as->load32(tagAddr, tagReg); if (binop->op == IR::OpNotEqual) qSwap(trueBlock, falseBlock); - Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal))); - Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal))); + Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal))); + Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal))); tagAddr.offset -= 4; _as->load32(tagAddr, tagReg); - Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0)); + Jump isNotUndefinedValue = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(0)); _as->addPatch(trueBlock, isNull); _as->addPatch(falseBlock, isNotUndefinedTag); _as->addPatch(falseBlock, isNotUndefinedValue); @@ -1797,7 +1602,8 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin } -void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock, +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); @@ -1808,18 +1614,55 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru IR::Expr *left = binop->left; IR::Expr *right = binop->right; - generateRuntimeCall(Assembler::ReturnValueRegister, compareEqual, - Assembler::PointerToValue(left), Assembler::PointerToValue(right)); - _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? Assembler::NotEqual : Assembler::Equal, - Assembler::ReturnValueRegister, Assembler::TrustedImm32(0), + 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); } -QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading() +template <typename JITAssembler> +QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createUnitForLoading() { QQmlRefPointer<CompiledData::CompilationUnit> result; result.adopt(new JIT::CompilationUnit); return result; } +QT_BEGIN_NAMESPACE +namespace QV4 { namespace JIT { +template class Q_QML_EXPORT InstructionSelection<>; +template class Q_QML_EXPORT ISelFactory<>; +#if defined(V4_BOOTSTRAP) + +Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture) +{ + using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>; + using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>; + + if (architecture == QLatin1String("armv7")) + return new ISelFactory<ARMv7CrossAssembler>; + else if (architecture == QLatin1String("armv8")) + return new ISelFactory<ARM64CrossAssembler>; + + QString hostArch; +#if CPU(ARM_THUMB2) + hostArch = QStringLiteral("armv7"); +#elif CPU(MIPS) + hostArch = QStringLiteral("mips"); +#elif CPU(X86) + hostArch = QStringLiteral("x86"); +#elif CPU(X86_64) + hostArch = QStringLiteral("x86_64"); +#endif + if (!hostArch.isEmpty() && architecture == hostArch) + return new ISelFactory<>; + + return nullptr; +} + +#endif +} } +QT_END_NAMESPACE + #endif // ENABLE(ASSEMBLER) |