Minor assembler cleanup

Move code from the Assembler helper-class into the .cpp file that has
the rest of the Assembler class implementation.

Change-Id: I4e9fb264216a078a3ee11119d7610fd108ddf8c7
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Simon Hausmann 2017-01-06 14:06:31 +01:00
parent 07a55e28a8
commit 3215ebbc33
2 changed files with 172 additions and 169 deletions

View File

@ -52,6 +52,8 @@
#include <WTFStubs.h>
#include <iostream>
#include <QBuffer>
#include <QCoreApplication>
#if ENABLE(ASSEMBLER)
@ -496,4 +498,174 @@ void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersT
_stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave));
}
namespace {
class QIODevicePrintStream: public FilePrintStream
{
Q_DISABLE_COPY(QIODevicePrintStream)
public:
explicit QIODevicePrintStream(QIODevice *dest)
: FilePrintStream(0)
, dest(dest)
, buf(4096, '0')
{
Q_ASSERT(dest);
}
~QIODevicePrintStream()
{}
void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
{
const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
if (written > 0)
dest->write(buf.constData(), written);
memset(buf.data(), 0, qMin(written, buf.size()));
}
void flush()
{}
private:
QIODevice *dest;
QByteArray buf;
};
} // anonymous namespace
static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions)
{
for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
it != end; ++it) {
const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = processedOutput.indexOf(ptrString);
if (idx < 0)
continue;
idx = processedOutput.lastIndexOf('\n', idx);
if (idx < 0)
continue;
processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value());
}
qDebug("%s", processedOutput.constData());
}
#if defined(Q_OS_LINUX)
static FILE *pmap;
static void qt_closePmap()
{
if (pmap) {
fclose(pmap);
pmap = 0;
}
}
#endif
JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
{
Label endOfCode = label();
{
for (size_t i = 0, ei = _patches.size(); i != ei; ++i) {
Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
for (Jump jump : qAsConst(_patches.at(i)))
jump.linkTo(target, this);
}
}
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
// link exception handlers
for (Jump jump : qAsConst(exceptionPropagationJumps))
linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
{
for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) {
Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
for (DataLabelPtr label : _labelPatches.at(i))
linkBuffer.patch(label, linkBuffer.locationOf(target));
}
}
*codeSize = linkBuffer.offsetOf(endOfCode);
QByteArray name;
JSC::MacroAssemblerCodeRef codeRef;
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
if (showCode) {
QHash<void*, const char*> functions;
#ifndef QT_NO_DEBUG
for (CallInfo call : qAsConst(_callInfos))
functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName;
#endif
QBuffer buf;
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
name = _function->name->toUtf8();
if (name.isEmpty())
name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
printDisassembledOutputWithCalls(buf.data(), functions);
} else {
codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
}
#if defined(Q_OS_LINUX)
// This implements writing of JIT'd addresses so that perf can find the
// symbol names.
//
// Perf expects the mapping to be in a certain place and have certain
// content, for more information, see:
// https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
static bool profileInitialized = false;
if (doProfile && !profileInitialized) {
profileInitialized = true;
char pname[PATH_MAX];
snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map",
(unsigned long)QCoreApplication::applicationPid());
pmap = fopen(pname, "w");
if (!pmap)
qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname);
// make sure we clean up nicely
std::atexit(qt_closePmap);
}
if (pmap) {
// this may have been pre-populated, if QV4_SHOW_ASM was on
if (name.isEmpty()) {
name = _function->name->toUtf8();
if (name.isEmpty())
name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
}
fprintf(pmap, "%llx %x %.*s\n",
(long long unsigned int)codeRef.code().executableAddress(),
*codeSize,
name.length(),
name.constData());
fflush(pmap);
}
#endif
return codeRef;
}
#endif

View File

@ -68,175 +68,6 @@ using namespace QV4;
using namespace QV4::JIT;
namespace {
class QIODevicePrintStream: public FilePrintStream
{
Q_DISABLE_COPY(QIODevicePrintStream)
public:
explicit QIODevicePrintStream(QIODevice *dest)
: FilePrintStream(0)
, dest(dest)
, buf(4096, '0')
{
Q_ASSERT(dest);
}
~QIODevicePrintStream()
{}
void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
{
const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
if (written > 0)
dest->write(buf.constData(), written);
memset(buf.data(), 0, qMin(written, buf.size()));
}
void flush()
{}
private:
QIODevice *dest;
QByteArray buf;
};
} // anonymous namespace
static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions)
{
for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
it != end; ++it) {
const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = processedOutput.indexOf(ptrString);
if (idx < 0)
continue;
idx = processedOutput.lastIndexOf('\n', idx);
if (idx < 0)
continue;
processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value());
}
qDebug("%s", processedOutput.constData());
}
#if defined(Q_OS_LINUX)
static FILE *pmap;
static void qt_closePmap()
{
if (pmap) {
fclose(pmap);
pmap = 0;
}
}
#endif
JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
{
Label endOfCode = label();
{
for (size_t i = 0, ei = _patches.size(); i != ei; ++i) {
Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
for (Jump jump : qAsConst(_patches.at(i)))
jump.linkTo(target, this);
}
}
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
// link exception handlers
for (Jump jump : qAsConst(exceptionPropagationJumps))
linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel));
{
for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) {
Label target = _addrs.at(i);
Q_ASSERT(target.isSet());
for (DataLabelPtr label : _labelPatches.at(i))
linkBuffer.patch(label, linkBuffer.locationOf(target));
}
}
*codeSize = linkBuffer.offsetOf(endOfCode);
QByteArray name;
JSC::MacroAssemblerCodeRef codeRef;
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
if (showCode) {
QHash<void*, const char*> functions;
#ifndef QT_NO_DEBUG
for (CallInfo call : qAsConst(_callInfos))
functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName;
#endif
QBuffer buf;
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
name = _function->name->toUtf8();
if (name.isEmpty())
name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
printDisassembledOutputWithCalls(buf.data(), functions);
} else {
codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
}
#if defined(Q_OS_LINUX)
// This implements writing of JIT'd addresses so that perf can find the
// symbol names.
//
// Perf expects the mapping to be in a certain place and have certain
// content, for more information, see:
// https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
static bool profileInitialized = false;
if (doProfile && !profileInitialized) {
profileInitialized = true;
char pname[PATH_MAX];
snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map",
(unsigned long)QCoreApplication::applicationPid());
pmap = fopen(pname, "w");
if (!pmap)
qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname);
// make sure we clean up nicely
std::atexit(qt_closePmap);
}
if (pmap) {
// this may have been pre-populated, if QV4_SHOW_ASM was on
if (name.isEmpty()) {
name = _function->name->toUtf8();
if (name.isEmpty())
name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')';
}
fprintf(pmap, "%llx %x %.*s\n",
(long long unsigned int)codeRef.code().executableAddress(),
*codeSize,
name.length(),
name.constData());
fflush(pmap);
}
#endif
return codeRef;
}
InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)