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:
parent
07a55e28a8
commit
3215ebbc33
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue