diff options
Diffstat (limited to 'src/qml/jit/qv4assemblercommon.cpp')
-rw-r--r-- | src/qml/jit/qv4assemblercommon.cpp | 159 |
1 files changed, 64 insertions, 95 deletions
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp index 831496a628..2b33d0aa10 100644 --- a/src/qml/jit/qv4assemblercommon.cpp +++ b/src/qml/jit/qv4assemblercommon.cpp @@ -1,62 +1,30 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <QBuffer> #include <QFile> +#include <QLoggingCategory> #include "qv4engine_p.h" #include "qv4assemblercommon_p.h" #include <private/qv4function_p.h> +#include <private/qv4functiontable_p.h> #include <private/qv4runtime_p.h> #include <assembler/MacroAssemblerCodeRef.h> #include <assembler/LinkBuffer.h> #include <WTFStubs.h> -#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES +#if QT_CONFIG(qml_jit) -#ifdef V4_ENABLE_JIT +#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES QT_BEGIN_NAMESPACE namespace QV4 { namespace JIT { +Q_LOGGING_CATEGORY(lcAsm, "qt.qml.v4.asm") + namespace { class QIODevicePrintStream: public FilePrintStream { @@ -74,15 +42,25 @@ public: ~QIODevicePrintStream() {} - void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) + void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0) { - const int written = qvsnprintf(buf.data(), buf.size(), format, argList); - if (written > 0) - dest->write(buf.constData(), written); - memset(buf.data(), 0, qMin(written, buf.size())); + const int printed = qvsnprintf(buf.data(), buf.size(), format, argList); + Q_ASSERT(printed <= buf.size()); + + qint64 written = 0; + while (written < printed) { + const qint64 result = dest->write(buf.constData() + written, printed - written); + if (result < 0) + break; + written += result; + } + + Q_ASSERT(written <= buf.size()); + Q_ASSERT(written >= 0); + memset(buf.data(), 0, size_t(written)); } - void flush() + void flush() override {} private: @@ -94,8 +72,9 @@ private: static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<const void*, const char*>& functions) { - for (QHash<const void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); - it != end; ++it) { + const auto symbols = Runtime::symbolTable(); + const QByteArray padding(" ; "); + for (auto it = functions.begin(), end = functions.end(); it != end; ++it) { const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); int idx = 0; while (idx >= 0) { @@ -105,22 +84,16 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, idx = processedOutput.indexOf('\n', idx); if (idx < 0) break; - processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; ") + it.value()); + const char *functionName = it.value(); + processedOutput = processedOutput.insert( + idx, QByteArray(padding + QByteArray( + functionName ? functionName : symbols[it.key()]))); } } - qDebug("%s", processedOutput.constData()); -} - -static QByteArray functionName(Function *function) -{ - QByteArray name = function->name()->toQString().toUtf8(); - if (name.isEmpty()) { - name = QByteArray::number(reinterpret_cast<quintptr>(function), 16); - name.prepend("QV4::Function(0x"); - name.append(')'); - } - return name; + auto lines = processedOutput.split('\n'); + for (const auto &line : lines) + qCDebug(lcAsm, "%s", line.constData()); } JIT::PlatformAssemblerCommon::~PlatformAssemblerCommon() @@ -141,14 +114,16 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind) JSC::MacroAssemblerCodeRef codeRef; - static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); + static const bool showCode = lcAsm().isDebugEnabled(); if (showCode) { QBuffer buf; buf.open(QIODevice::WriteOnly); WTF::setDataFile(new QIODevicePrintStream(&buf)); - QByteArray name = functionName(function); - codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, "function %s", name.constData()); + // We use debugAddress here because it's actually for debugging and hidden behind an + // environment variable. + const QByteArray name = Function::prettyName(function, linkBuffer.debugAddress()).toUtf8(); + codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, name.constData()); WTF::setDataFile(stderr); printDisassembledOutputWithCalls(buf.data(), functions); @@ -159,31 +134,10 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind) function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef); function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress()); - // This implements writing of JIT'd addresses so that perf can find the - // symbol names. - // - // Perf expects the mapping to be in a certain place and have certain - // content, for more information, see: - // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt - static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); - if (Q_UNLIKELY(doProfile)) { - static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map") - .arg(QCoreApplication::applicationPid())); - static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly); - if (!isOpen) { - qWarning("QV4::JIT::Assembler: Cannot write perf map file."); - doProfile = false; - } else { - perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>( - codeRef.code().executableAddress()), 16)); - perfMapFile.putChar(' '); - perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef.size()), 16)); - perfMapFile.putChar(' '); - perfMapFile.write(functionName(function)); - perfMapFile.putChar('\n'); - perfMapFile.flush(); - } - } + generateFunctionTable(function, &codeRef); + + if (Q_UNLIKELY(!linkBuffer.makeExecutable())) + function->jittedCode = nullptr; // The function is not executable, but the coderef exists. } void PlatformAssemblerCommon::prepareCallWithArgCount(int argc) @@ -201,7 +155,7 @@ void PlatformAssemblerCommon::prepareCallWithArgCount(int argc) void PlatformAssemblerCommon::storeInstructionPointer(int instructionOffset) { - Address addr(CppStackFrameRegister, offsetof(QV4::CppStackFrame, instructionPointer)); + Address addr(CppStackFrameRegister, offsetof(QV4::JSTypesStackFrame, instructionPointer)); store32(TrustedImm32(instructionOffset), addr); } @@ -316,27 +270,42 @@ void PlatformAssemblerCommon::passInt32AsArg(int value, int arg) store32(TrustedImm32(value), argStackAddress(arg)); } -void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *funcPtr) +void JIT::PlatformAssemblerCommon::passPointerAsArg(void *ptr, int arg) +{ +#ifndef QT_NO_DEBUG + Q_ASSERT(arg < remainingArgcForCall); + --remainingArgcForCall; +#endif + + if (arg < ArgInRegCount) + move(TrustedImmPtr(ptr), registerForArg(arg)); + else + storePtr(TrustedImmPtr(ptr), argStackAddress(arg)); +} + +void PlatformAssemblerCommon::callRuntime(const void *funcPtr, const char *functionName) { #ifndef QT_NO_DEBUG Q_ASSERT(remainingArgcForCall == 0); remainingArgcForCall = NoCall; #endif - callRuntimeUnchecked(functionName, funcPtr); + callRuntimeUnchecked(funcPtr, functionName); if (argcOnStackForCall > 0) { addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister); argcOnStackForCall = 0; } } -void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr) +void PlatformAssemblerCommon::callRuntimeUnchecked(const void *funcPtr, const char *functionName) { + Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr)); functions.insert(funcPtr, functionName); callAbsolute(funcPtr); } -void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr) +void PlatformAssemblerCommon::tailCallRuntime(const void *funcPtr, const char *functionName) { + Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr)); functions.insert(funcPtr, functionName); setTailCallArg(EngineRegister, 1); setTailCallArg(CppStackFrameRegister, 0); @@ -379,4 +348,4 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr) QT_END_NAMESPACE -#endif // V4_ENABLE_JIT +#endif // QT_CONFIG(qml_jit) |