diff options
Diffstat (limited to 'src/qml/jit/qv4isel_masm.cpp')
-rw-r--r-- | src/qml/jit/qv4isel_masm.cpp | 188 |
1 files changed, 153 insertions, 35 deletions
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index da511cd1eb..6de6524615 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -45,6 +45,7 @@ #include "qv4binop_p.h" #include <QtCore/QBuffer> +#include <QtCore/QCoreApplication> #include <assembler/LinkBuffer.h> #include <WTFStubs.h> @@ -120,6 +121,19 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q qDebug("%s", processedOutput.constData()); } +#if defined(Q_OS_LINUX) +static FILE *pmap; + +static void qt_closePmap() +{ + if (pmap) { + fclose(pmap); + pmap = 0; + } +} + +#endif + JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) { Label endOfCode = label(); @@ -167,19 +181,21 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) *codeSize = linkBuffer.offsetOf(endOfCode); + QByteArray name; + JSC::MacroAssemblerCodeRef codeRef; - static bool showCode = !qgetenv("QV4_SHOW_ASM").isNull(); + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); if (showCode) { QBuffer buf; buf.open(QIODevice::WriteOnly); WTF::setDataFile(new QIODevicePrintStream(&buf)); - QByteArray name = _function->name->toUtf8(); + name = _function->name->toUtf8(); if (name.isEmpty()) { name = QByteArray::number(quintptr(_function), 16); name.prepend("IR::Function(0x"); - name.append(")"); + name.append(')'); } codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data()); @@ -189,6 +205,50 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); } +#if defined(Q_OS_LINUX) + // This implements writing of JIT'd addresses so that perf can find the + // symbol names. + // + // Perf expects the mapping to be in a certain place and have certain + // content, for more information, see: + // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt + static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); + static bool profileInitialized = false; + if (doProfile && !profileInitialized) { + profileInitialized = true; + + char pname[PATH_MAX]; + snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", + (unsigned long)QCoreApplication::applicationPid()); + + pmap = fopen(pname, "w"); + if (!pmap) + qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); + + // make sure we clean up nicely + std::atexit(qt_closePmap); + } + + if (pmap) { + // this may have been pre-populated, if QV4_SHOW_ASM was on + if (name.isEmpty()) { + name = _function->name->toUtf8(); + if (name.isEmpty()) { + name = QByteArray::number(quintptr(_function), 16); + name.prepend("IR::Function(0x"); + name.append(')'); + } + } + + fprintf(pmap, "%llx %x %.*s\n", + (long long unsigned int)codeRef.code().executableAddress(), + *codeSize, + name.length(), + name.constData()); + fflush(pmap); + } +#endif + return codeRef; } @@ -215,7 +275,7 @@ void InstructionSelection::run(int functionIndex) IR::Optimizer opt(_function); opt.run(qmlEngine); - static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty(); + static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC"); if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { RegisterAllocator regalloc(Assembler::getRegisterInfo()); regalloc.run(_function, opt); @@ -317,7 +377,7 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values) QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep() { QQmlRefPointer<QV4::CompiledData::CompilationUnit> result; - result.take(compilationUnit.take()); + result.adopt(compilationUnit.take()); return result; } @@ -339,6 +399,23 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args } } +void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base, + IR::Member::MemberKind kind, + int propertyIndex, IR::Expr *result) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) { + generateFunctionCall(result, Runtime::typeofScopeObjectProperty, Assembler::EngineRegister, + Assembler::PointerToValue(base), + Assembler::TrustedImm32(propertyIndex)); + } else if (kind == IR::Member::MemberOfQmlContextObject) { + generateFunctionCall(result, Runtime::typeofContextObjectProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImm32(propertyIndex)); + } else { + Q_UNREACHABLE(); + } +} + void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) { @@ -574,9 +651,9 @@ void InstructionSelection::loadThisObject(IR::Expr *temp) #endif } -void InstructionSelection::loadQmlIdArray(IR::Expr *temp) +void InstructionSelection::loadQmlContext(IR::Expr *temp) { - generateFunctionCall(temp, Runtime::getQmlIdArray, Assembler::EngineRegister); + generateFunctionCall(temp, Runtime::getQmlContext, Assembler::EngineRegister); } void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) @@ -584,16 +661,6 @@ void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) generateFunctionCall(temp, Runtime::getQmlImportedScripts, Assembler::EngineRegister); } -void InstructionSelection::loadQmlContextObject(IR::Expr *temp) -{ - generateFunctionCall(temp, Runtime::getQmlContextObject, Assembler::EngineRegister); -} - -void InstructionSelection::loadQmlScopeObject(IR::Expr *temp) -{ - generateFunctionCall(temp, Runtime::getQmlScopeObject, Assembler::EngineRegister); -} - void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name)); @@ -614,7 +681,7 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target) _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32), + _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()), (Assembler::RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); @@ -631,7 +698,7 @@ void InstructionSelection::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); -#if QT_POINTER_SIZE == 8 +#ifdef QV4_USE_64_BIT_VALUE_ENCODING _as->store64(Assembler::ReturnValueRegister, destAddr); #else _as->store32(Assembler::ReturnValueRegister, destAddr); @@ -680,6 +747,18 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR:: } } +void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, IR::Expr *target) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(target, Runtime::getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(target, Runtime::getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else if (kind == IR::Member::MemberOfIdObjectsArray) + generateFunctionCall(target, Runtime::getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); + else + Q_ASSERT(false); +} + void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) @@ -708,6 +787,18 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase, } } +void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) +{ + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(Assembler::Void, Runtime::setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), + Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(Assembler::Void, Runtime::setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), + Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); + else + Q_ASSERT(false); +} + void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) { generateFunctionCall(Assembler::Void, Runtime::setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase), @@ -901,6 +992,24 @@ void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr binop.generate(leftSource, rightSource, target); } +void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result) +{ + prepareCallData(args, base); + + if (kind == IR::Member::MemberOfQmlScopeObject) + generateFunctionCall(result, Runtime::callQmlScopeObjectProperty, + Assembler::EngineRegister, + Assembler::TrustedImm32(propertyIndex), + baseAddressForCallData()); + else if (kind == IR::Member::MemberOfQmlContextObject) + generateFunctionCall(result, Runtime::callQmlContextObjectProperty, + Assembler::EngineRegister, + Assembler::TrustedImm32(propertyIndex), + baseAddressForCallData()); + else + Q_ASSERT(false); +} + void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { @@ -993,7 +1102,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe // not an int, check if it's NOT a double: isNoInt.link(_as); -#if QT_POINTER_SIZE == 8 +#ifdef QV4_USE_64_BIT_VALUE_ENCODING _as->and32(Assembler::TrustedImm32(Value::IsDouble_Mask), Assembler::ScratchRegister); Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); @@ -1011,7 +1120,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { -#if QT_POINTER_SIZE == 8 +#if Q_PROCESSOR_WORDSIZE == 8 _as->load64(addr2, Assembler::ScratchRegister); _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target)); #else @@ -1080,7 +1189,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *targe switch (source->type) { case IR::VarType: { -#if QT_POINTER_SIZE == 8 +#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); @@ -1297,11 +1406,11 @@ void InstructionSelection::visitCJump(IR::CJump *s) } else { Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond); Address tag = temp; - tag.offset += qOffsetOf(QV4::Value, tag); + tag.offset += QV4::Value::tagOffset(); Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type)); Address data = temp; - data.offset += qOffsetOf(QV4::Value, int_32); + data.offset += QV4::Value::valueOffset(); _as->load32(data, Assembler::ReturnValueRegister); Assembler::Jump testBoolean = _as->jump(); @@ -1383,11 +1492,14 @@ void InstructionSelection::visitRet(IR::Ret *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) +#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; @@ -1472,13 +1584,16 @@ void InstructionSelection::visitRet(IR::Ret *s) } 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); + _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); + _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.val), Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); #endif } else { Q_UNREACHABLE(); @@ -1499,13 +1614,16 @@ void InstructionSelection::visitRet(IR::Ret *s) _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); + _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); + _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.val), Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister); #endif _as->jump(leaveStackFrame); } |