7#include <QLoggingCategory>
11#include <private/qv4function_p.h>
12#include <private/qv4functiontable_p.h>
13#include <private/qv4runtime_p.h>
15#include <assembler/MacroAssemblerCodeRef.h>
16#include <assembler/LinkBuffer.h>
23#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
29Q_STATIC_LOGGING_CATEGORY(lcAsm,
"qt.qml.v4.asm")
32class QIODevicePrintStream:
public FilePrintStream
34 Q_DISABLE_COPY(QIODevicePrintStream)
37 explicit QIODevicePrintStream(QIODevice *dest)
38 : FilePrintStream(
nullptr)
45 ~QIODevicePrintStream()
48 void vprintf(
const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0)
50 const int printed = std::vsnprintf(buf.data(), buf.size(), format, argList);
51 Q_ASSERT(printed <= buf.size());
54 while (written < printed) {
55 const qint64 result = dest->write(buf.constData() + written, printed - written);
61 Q_ASSERT(written <= buf.size());
62 Q_ASSERT(written >= 0);
63 memset(buf.data(), 0, size_t(written));
75static void printDisassembledOutputWithCalls(QByteArray processedOutput,
76 const QHash<
const void*,
const char*>& functions)
78 const auto symbols = Runtime::symbolTable();
79 const QByteArray padding(
" ; ");
80 for (
auto it = functions.begin(), end = functions.end(); it != end; ++it) {
81 const QByteArray ptrString =
"0x" + QByteArray::number(quintptr(it.key()), 16);
84 idx = processedOutput.indexOf(ptrString, idx);
87 idx = processedOutput.indexOf(
'\n', idx);
90 const char *functionName = it.value();
91 processedOutput = processedOutput.insert(
92 idx, QByteArray(padding + QByteArray(
93 functionName ? functionName : symbols[it.key()])));
97 auto lines = processedOutput.split(
'\n');
98 for (
const auto &line : lines)
99 qCDebug(lcAsm,
"%s", line.constData());
102JIT::PlatformAssemblerCommon::~PlatformAssemblerCommon()
105void PlatformAssemblerCommon::link(Function *function,
const char *jitKind)
107 for (
const auto &jumpTarget : jumpsToLink)
108 jumpTarget.jump.linkTo(labelForOffset[jumpTarget.offset],
this);
110 JSC::JSGlobalData dummy(function->internalClass->engine->executableAllocator);
111 JSC::LinkBuffer<MacroAssembler> linkBuffer(dummy,
this,
nullptr);
113 for (
const auto &ehTarget : ehTargets) {
114 auto targetLabel = labelForOffset.value(ehTarget.offset);
115 linkBuffer.patch(ehTarget.label, linkBuffer.locationOf(targetLabel));
118 JSC::MacroAssemblerCodeRef codeRef;
120 static const bool showCode = lcAsm().isDebugEnabled();
123 buf.open(QIODevice::WriteOnly);
124 WTF::setDataFile(
new QIODevicePrintStream(&buf));
128 const QByteArray name = Function::prettyName(function, linkBuffer.debugAddress()).toUtf8();
129 codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, name.constData());
131 WTF::setDataFile(stderr);
132 printDisassembledOutputWithCalls(buf.data(), functions);
134 codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
137 function->codeRef =
new JSC::MacroAssemblerCodeRef(codeRef);
138 function->jittedCode =
reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
140 generateFunctionTable(function, &codeRef);
142 if (Q_UNLIKELY(!linkBuffer.makeExecutable()))
143 function->jittedCode =
nullptr;
146void PlatformAssemblerCommon::prepareCallWithArgCount(
int argc)
149 Q_ASSERT(remainingArgcForCall == NoCall);
150 remainingArgcForCall = argc;
153 if (argc > ArgInRegCount) {
154 argcOnStackForCall =
int(WTF::roundUpToMultipleOf(16, size_t(argc - ArgInRegCount) * PointerSize));
155 subPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
159void PlatformAssemblerCommon::storeInstructionPointer(
int instructionOffset)
161 Address addr(CppStackFrameRegister, offsetof(QV4::JSTypesStackFrame, instructionPointer));
162 store32(TrustedImm32(instructionOffset), addr);
165PlatformAssemblerCommon::Address PlatformAssemblerCommon::argStackAddress(
int arg)
167 int offset = arg - ArgInRegCount;
168 Q_ASSERT(offset >= 0);
169 return Address(StackPointerRegister, offset * PointerSize);
172void PlatformAssemblerCommon::passAccumulatorAsArg(
int arg)
175 Q_ASSERT(arg < remainingArgcForCall);
176 --remainingArgcForCall;
179 passAccumulatorAsArg_internal(arg,
false);
182void JIT::PlatformAssemblerCommon::pushAccumulatorAsArg(
int arg)
184 passAccumulatorAsArg_internal(arg,
true);
187void PlatformAssemblerCommon::passAccumulatorAsArg_internal(
int arg,
bool doPush)
189 if (arg < ArgInRegCount) {
190 addPtr(TrustedImm32(offsetof(CallData, accumulator)), JSStackFrameRegister, registerForArg(arg));
192 addPtr(TrustedImm32(offsetof(CallData, accumulator)), JSStackFrameRegister, ScratchRegister);
194 push(ScratchRegister);
196 storePtr(ScratchRegister, argStackAddress(arg));
200void PlatformAssemblerCommon::passFunctionAsArg(
int arg)
203 Q_ASSERT(arg < remainingArgcForCall);
204 --remainingArgcForCall;
207 if (arg < ArgInRegCount) {
208 loadFunctionPtr(registerForArg(arg));
210 loadFunctionPtr(ScratchRegister);
211 storePtr(ScratchRegister, argStackAddress(arg));
215void PlatformAssemblerCommon::passEngineAsArg(
int arg)
218 Q_ASSERT(arg < remainingArgcForCall);
219 --remainingArgcForCall;
222 if (arg < ArgInRegCount) {
223 move(EngineRegister, registerForArg(arg));
225 storePtr(EngineRegister, argStackAddress(arg));
229void PlatformAssemblerCommon::passJSSlotAsArg(
int reg,
int arg)
231 Address addr(JSStackFrameRegister, reg *
int(
sizeof(QV4::Value)));
232 passAddressAsArg(addr, arg);
235void JIT::PlatformAssemblerCommon::passAddressAsArg(Address addr,
int arg)
238 Q_ASSERT(arg < remainingArgcForCall);
239 --remainingArgcForCall;
242 if (arg < ArgInRegCount) {
243 addPtr(TrustedImm32(addr.offset), addr.base, registerForArg(arg));
245 addPtr(TrustedImm32(addr.offset), addr.base, ScratchRegister);
246 storePtr(ScratchRegister, argStackAddress(arg));
250void PlatformAssemblerCommon::passCppFrameAsArg(
int arg)
253 Q_ASSERT(arg < remainingArgcForCall);
254 --remainingArgcForCall;
257 if (arg < ArgInRegCount)
258 move(CppStackFrameRegister, registerForArg(arg));
260 store32(CppStackFrameRegister, argStackAddress(arg));
263void PlatformAssemblerCommon::passInt32AsArg(
int value,
int arg)
266 Q_ASSERT(arg < remainingArgcForCall);
267 --remainingArgcForCall;
270 if (arg < ArgInRegCount)
271 move(TrustedImm32(value), registerForArg(arg));
273 store32(TrustedImm32(value), argStackAddress(arg));
276void JIT::PlatformAssemblerCommon::passPointerAsArg(
void *ptr,
int arg)
279 Q_ASSERT(arg < remainingArgcForCall);
280 --remainingArgcForCall;
283 if (arg < ArgInRegCount)
284 move(TrustedImmPtr(ptr), registerForArg(arg));
286 storePtr(TrustedImmPtr(ptr), argStackAddress(arg));
289void PlatformAssemblerCommon::callRuntime(
const void *funcPtr,
const char *functionName)
292 Q_ASSERT(remainingArgcForCall == 0);
293 remainingArgcForCall = NoCall;
295 callRuntimeUnchecked(funcPtr, functionName);
296 if (argcOnStackForCall > 0) {
297 addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
298 argcOnStackForCall = 0;
302void PlatformAssemblerCommon::callRuntimeUnchecked(
const void *funcPtr,
const char *functionName)
304 Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
305 functions.insert(funcPtr, functionName);
306 callAbsolute(funcPtr);
309void PlatformAssemblerCommon::tailCallRuntime(
const void *funcPtr,
const char *functionName)
311 Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
312 functions.insert(funcPtr, functionName);
313 setTailCallArg(EngineRegister, 1);
314 setTailCallArg(CppStackFrameRegister, 0);
316 generatePlatformFunctionExit(
true);
317 jumpAbsolute(funcPtr);
320void PlatformAssemblerCommon::setTailCallArg(RegisterID src,
int arg)
322 if (arg < ArgInRegCount) {
323 move(src, registerForArg(arg));
331JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::jsAlloca(
int slotCount)
333 Address jsStackTopAddr(EngineRegister, offsetof(EngineBase, jsStackTop));
334 RegisterID jsStackTop = AccumulatorRegisterValue;
335 loadPtr(jsStackTopAddr, jsStackTop);
336 addPtr(TrustedImm32(
sizeof(Value) * slotCount), jsStackTop);
337 storePtr(jsStackTop, jsStackTopAddr);
338 return Address(jsStackTop, 0);
341void PlatformAssemblerCommon::storeInt32AsValue(
int srcInt, Address destAddr)
343 store32(TrustedImm32(srcInt),
344 Address(destAddr.base, destAddr.offset + QV4::Value::valueOffset()));
345 store32(TrustedImm32(
int(QV4::Value::ValueTypeInternal::Integer)),
346 Address(destAddr.base, destAddr.offset + QV4::Value::tagOffset()));