fix: comprehensive boot warnings and exceptions — fixable silenced, unfixable diagnosed

Build system (5 gaps hardened):
- COOKBOOK_OFFLINE defaults to true (fork-mode)
- normalize_patch handles diff -ruN format
- New 'repo validate-patches' command (25/25 relibc patches)
- 14 patched Qt/Wayland/display recipes added to protected list
- relibc archive regenerated with current patch chain

Boot fixes (fixable):
- Full ISO EFI partition: 16 MiB → 1 MiB (matches mini, BIOS hardcoded 2 MiB offset)
- D-Bus system bus: absolute /usr/bin/dbus-daemon path (was skipped)
- redbear-sessiond: absolute /usr/bin/redbear-sessiond path (was skipped)
- daemon framework: silenced spurious INIT_NOTIFY warnings for oneshot_async services (P0-daemon-silence-init-notify.patch)
- udev-shim: demoted INIT_NOTIFY warning to INFO (expected for oneshot_async)
- relibc: comprehensive named semaphores (sem_open/close/unlink) replacing upstream todo!() stubs
- greeterd: Wayland socket timeout 15s → 30s (compositor DRM wait)
- greeter-ui: built and linked (header guard unification, sem_compat stubs removed)
- mc: un-ignored in both configs, fixed glib/libiconv/pcre2 transitive deps
- greeter config: removed stale keymapd dependency from display/greeter services
- prefix toolchain: relibc headers synced, _RELIBC_STDLIB_H guard unified

Unfixable (diagnosed, upstream):
- i2c-hidd: abort on no-I2C-hardware (QEMU) — process::exit → relibc abort
- kded6/greeter-ui: page fault 0x8 — Qt library null deref
- Thread panics fd != -1 — Rust std library on Redox
- DHCP timeout / eth0 MAC — QEMU user-mode networking
- hwrngd/thermald — no hardware RNG/thermal in VM
- live preload allocation — BIOS memory fragmentation, continues on demand
This commit is contained in:
2026-05-05 20:20:37 +01:00
parent a5f97b6632
commit f31522130f
81834 changed files with 11051982 additions and 108 deletions
@@ -0,0 +1,354 @@
// 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
// Qt-Security score:critical reason:jit
#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>
#include <cstdio>
#if QT_CONFIG(qml_jit)
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
Q_STATIC_LOGGING_CATEGORY(lcAsm, "qt.qml.v4.asm")
namespace {
class QIODevicePrintStream: public FilePrintStream
{
Q_DISABLE_COPY(QIODevicePrintStream)
public:
explicit QIODevicePrintStream(QIODevice *dest)
: FilePrintStream(nullptr)
, dest(dest)
, buf(4096, '0')
{
Q_ASSERT(dest);
}
~QIODevicePrintStream()
{}
void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0)
{
const int printed = std::vsnprintf(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() override
{}
private:
QIODevice *dest;
QByteArray buf;
};
} // anonymous namespace
static void printDisassembledOutputWithCalls(QByteArray processedOutput,
const QHash<const void*, const char*>& functions)
{
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) {
idx = processedOutput.indexOf(ptrString, idx);
if (idx < 0)
break;
idx = processedOutput.indexOf('\n', idx);
if (idx < 0)
break;
const char *functionName = it.value();
processedOutput = processedOutput.insert(
idx, QByteArray(padding + QByteArray(
functionName ? functionName : symbols[it.key()])));
}
}
auto lines = processedOutput.split('\n');
for (const auto &line : lines)
qCDebug(lcAsm, "%s", line.constData());
}
JIT::PlatformAssemblerCommon::~PlatformAssemblerCommon()
{}
void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
{
for (const auto &jumpTarget : jumpsToLink)
jumpTarget.jump.linkTo(labelForOffset[jumpTarget.offset], this);
JSC::JSGlobalData dummy(function->internalClass->engine->executableAllocator);
JSC::LinkBuffer<MacroAssembler> linkBuffer(dummy, this, nullptr);
for (const auto &ehTarget : ehTargets) {
auto targetLabel = labelForOffset.value(ehTarget.offset);
linkBuffer.patch(ehTarget.label, linkBuffer.locationOf(targetLabel));
}
JSC::MacroAssemblerCodeRef codeRef;
static const bool showCode = lcAsm().isDebugEnabled();
if (showCode) {
QBuffer buf;
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
// 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);
} else {
codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
}
function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
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)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(remainingArgcForCall == NoCall);
remainingArgcForCall = argc;
#endif
if (argc > ArgInRegCount) {
argcOnStackForCall = int(WTF::roundUpToMultipleOf(16, size_t(argc - ArgInRegCount) * PointerSize));
subPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
}
}
void PlatformAssemblerCommon::storeInstructionPointer(int instructionOffset)
{
Address addr(CppStackFrameRegister, offsetof(QV4::JSTypesStackFrame, instructionPointer));
store32(TrustedImm32(instructionOffset), addr);
}
PlatformAssemblerCommon::Address PlatformAssemblerCommon::argStackAddress(int arg)
{
int offset = arg - ArgInRegCount;
Q_ASSERT(offset >= 0);
return Address(StackPointerRegister, offset * PointerSize);
}
void PlatformAssemblerCommon::passAccumulatorAsArg(int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
passAccumulatorAsArg_internal(arg, false);
}
void JIT::PlatformAssemblerCommon::pushAccumulatorAsArg(int arg)
{
passAccumulatorAsArg_internal(arg, true);
}
void PlatformAssemblerCommon::passAccumulatorAsArg_internal(int arg, bool doPush)
{
if (arg < ArgInRegCount) {
addPtr(TrustedImm32(offsetof(CallData, accumulator)), JSStackFrameRegister, registerForArg(arg));
} else {
addPtr(TrustedImm32(offsetof(CallData, accumulator)), JSStackFrameRegister, ScratchRegister);
if (doPush)
push(ScratchRegister);
else
storePtr(ScratchRegister, argStackAddress(arg));
}
}
void PlatformAssemblerCommon::passFunctionAsArg(int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
if (arg < ArgInRegCount) {
loadFunctionPtr(registerForArg(arg));
} else {
loadFunctionPtr(ScratchRegister);
storePtr(ScratchRegister, argStackAddress(arg));
}
}
void PlatformAssemblerCommon::passEngineAsArg(int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
if (arg < ArgInRegCount) {
move(EngineRegister, registerForArg(arg));
} else {
storePtr(EngineRegister, argStackAddress(arg));
}
}
void PlatformAssemblerCommon::passJSSlotAsArg(int reg, int arg)
{
Address addr(JSStackFrameRegister, reg * int(sizeof(QV4::Value)));
passAddressAsArg(addr, arg);
}
void JIT::PlatformAssemblerCommon::passAddressAsArg(Address addr, int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
if (arg < ArgInRegCount) {
addPtr(TrustedImm32(addr.offset), addr.base, registerForArg(arg));
} else {
addPtr(TrustedImm32(addr.offset), addr.base, ScratchRegister);
storePtr(ScratchRegister, argStackAddress(arg));
}
}
void PlatformAssemblerCommon::passCppFrameAsArg(int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
if (arg < ArgInRegCount)
move(CppStackFrameRegister, registerForArg(arg));
else
store32(CppStackFrameRegister, argStackAddress(arg));
}
void PlatformAssemblerCommon::passInt32AsArg(int value, int arg)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(arg < remainingArgcForCall);
--remainingArgcForCall;
#endif
if (arg < ArgInRegCount)
move(TrustedImm32(value), registerForArg(arg));
else
store32(TrustedImm32(value), argStackAddress(arg));
}
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(funcPtr, functionName);
if (argcOnStackForCall > 0) {
addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
argcOnStackForCall = 0;
}
}
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 void *funcPtr, const char *functionName)
{
Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName);
setTailCallArg(EngineRegister, 1);
setTailCallArg(CppStackFrameRegister, 0);
freeStackSpace();
generatePlatformFunctionExit(/*tailCall =*/ true);
jumpAbsolute(funcPtr);
}
void PlatformAssemblerCommon::setTailCallArg(RegisterID src, int arg)
{
if (arg < ArgInRegCount) {
move(src, registerForArg(arg));
} else {
// We never write to the incoming arguments space on the stack, and the tail call runtime
// method has the same signature as the jitted function, so it is safe for us to just reuse
// the arguments that we got in.
}
}
JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::jsAlloca(int slotCount)
{
Address jsStackTopAddr(EngineRegister, offsetof(EngineBase, jsStackTop));
RegisterID jsStackTop = AccumulatorRegisterValue;
loadPtr(jsStackTopAddr, jsStackTop);
addPtr(TrustedImm32(sizeof(Value) * slotCount), jsStackTop);
storePtr(jsStackTop, jsStackTopAddr);
return Address(jsStackTop, 0);
}
void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
{
store32(TrustedImm32(srcInt),
Address(destAddr.base, destAddr.offset + QV4::Value::valueOffset()));
store32(TrustedImm32(int(QV4::Value::ValueTypeInternal::Integer)),
Address(destAddr.base, destAddr.offset + QV4::Value::tagOffset()));
}
} // JIT namespace
} // QV4 namepsace
QT_END_NAMESPACE
#endif // QT_CONFIG(qml_jit)
@@ -0,0 +1,714 @@
// Copyright (C) 2018 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
// Qt-Security score:critical reason:jit
#ifndef QV4PLATFORMASSEMBLER_P_H
#define QV4PLATFORMASSEMBLER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qv4engine_p.h>
#include <private/qv4function_p.h>
#include <private/qv4global_p.h>
#include <private/qv4stackframe_p.h>
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
#include <QtCore/qhash.h>
#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
#if defined(Q_PROCESSOR_X86_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN) || defined(Q_OS_SOLARIS) || defined(Q_OS_VXWORKS) || defined(Q_OS_HURD)
class PlatformAssembler_X86_64_SysV : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
static constexpr int NativeStackAlignment = 16;
static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = RegisterID::eax;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = RegisterID::r10;
static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg5Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = RegisterID::r12;
static const RegisterID CppStackFrameRegister = RegisterID::r13;
static const RegisterID EngineRegister = RegisterID::r14;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const FPRegisterID FPScratchRegister2 = FPRegisterID::xmm2;
static const RegisterID Arg0Reg = RegisterID::edi;
static const RegisterID Arg1Reg = RegisterID::esi;
static const RegisterID Arg2Reg = RegisterID::edx;
static const RegisterID Arg3Reg = RegisterID::ecx;
static const RegisterID Arg4Reg = RegisterID::r8;
static const RegisterID Arg5Reg = RegisterID::r9;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 6;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_X86_64_SysV PlatformAssemblerBase;
#endif
#if defined(Q_OS_WIN)
class PlatformAssembler_Win64 : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = RegisterID::eax;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = RegisterID::r10;
static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg3Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = RegisterID::r12;
static const RegisterID CppStackFrameRegister = RegisterID::r13;
static const RegisterID EngineRegister = RegisterID::r14;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const RegisterID Arg0Reg = RegisterID::ecx;
static const RegisterID Arg1Reg = RegisterID::edx;
static const RegisterID Arg2Reg = RegisterID::r8;
static const RegisterID Arg3Reg = RegisterID::r9;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 4;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
subPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
call(ScratchRegister);
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_Win64 PlatformAssemblerBase;
#endif
#endif
#if (defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_X86_64)) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_X86_All : public JSC::MacroAssembler<JSC::MacroAssemblerX86>
{
public:
static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegisterValue = RegisterID::eax;
static const RegisterID ReturnValueRegisterTag = RegisterID::edx;
static const RegisterID ScratchRegister = RegisterID::ecx;
static const RegisterID AccumulatorRegisterValue = ReturnValueRegisterValue;
static const RegisterID AccumulatorRegisterTag = ReturnValueRegisterTag;
static const RegisterID JSStackFrameRegister = RegisterID::ebx;
static const RegisterID CppStackFrameRegister = RegisterID::esi;
static const RegisterID EngineRegister = RegisterID::edi;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const RegisterID Arg0Reg = NoRegister;
static const RegisterID Arg1Reg = NoRegister;
static const RegisterID Arg2Reg = NoRegister;
static const RegisterID Arg3Reg = NoRegister;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 0;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(RegisterID::ebp);
move(RegisterID::esp, RegisterID::ebp);
move(TrustedImmPtr(nullptr), AccumulatorRegisterValue); push(AccumulatorRegisterValue); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
// Ensure the stack is 16-byte aligned in order for compiler generated aligned SSE2
// instructions to be able to target the stack.
subPtr(TrustedImm32(8), StackPointerRegister);
loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister);
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(RegisterID::ebp);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_X86_All PlatformAssemblerBase;
#endif
#if defined(Q_PROCESSOR_ARM_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_ARM64 : public JSC::MacroAssembler<JSC::MacroAssemblerARM64>
{
public:
static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = JSC::ARM64Registers::x9;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = JSC::ARM64Registers::x10;
static const RegisterID ScratchRegister2 = JSC::ARM64Registers::x7; // Note: overlaps with Arg7Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = JSC::ARM64Registers::x19;
static const RegisterID CppStackFrameRegister = JSC::ARM64Registers::x20;
static const RegisterID EngineRegister = JSC::ARM64Registers::x21;
static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
static const FPRegisterID FPScratchRegister = JSC::ARM64Registers::q1;
static const RegisterID Arg0Reg = JSC::ARM64Registers::x0;
static const RegisterID Arg1Reg = JSC::ARM64Registers::x1;
static const RegisterID Arg2Reg = JSC::ARM64Registers::x2;
static const RegisterID Arg3Reg = JSC::ARM64Registers::x3;
static const RegisterID Arg4Reg = JSC::ARM64Registers::x4;
static const RegisterID Arg5Reg = JSC::ARM64Registers::x5;
static const RegisterID Arg6Reg = JSC::ARM64Registers::x6;
static const RegisterID Arg7Reg = JSC::ARM64Registers::x7;
static const int ArgInRegCount = 8;
void push(RegisterID src)
{
pushToSave(src);
}
void pop(RegisterID dest)
{
popToRestore(dest);
}
void pop()
{
add64(TrustedImm32(16), stackPointerRegister);
}
void popValue()
{
pop();
}
void generatePlatformFunctionEntry()
{
pushPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
move(RegisterID::sp, RegisterID::fp);
move(TrustedImmPtr(nullptr), AccumulatorRegister); // exceptionHandler
pushPair(JSStackFrameRegister, AccumulatorRegister);
pushPair(EngineRegister, CppStackFrameRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
if (!tailCall) // do not overwrite arg0 (used in the tail call)
move(AccumulatorRegister, ReturnValueRegister);
popPair(EngineRegister, CppStackFrameRegister);
popPair(JSStackFrameRegister, AccumulatorRegister);
popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
pushToSave(reg);
}
void popAligned(RegisterID reg)
{
popToRestore(reg);
}
};
typedef PlatformAssembler_ARM64 PlatformAssemblerBase;
#endif
#if defined(Q_PROCESSOR_ARM_32) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_ARM32 : public JSC::MacroAssembler<JSC::MacroAssemblerARMv7>
{
public:
static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegisterValue = JSC::ARMRegisters::r0;
static const RegisterID ReturnValueRegisterTag = JSC::ARMRegisters::r1;
static const RegisterID ScratchRegister = JSC::ARMRegisters::r2;
static const RegisterID AccumulatorRegisterValue = JSC::ARMRegisters::r4;
static const RegisterID AccumulatorRegisterTag = JSC::ARMRegisters::r5;
// r6 is used by MacroAssemblerARMv7
static const RegisterID JSStackFrameRegister = JSC::ARMRegisters::r8;
static const RegisterID CppStackFrameRegister = JSC::ARMRegisters::r10;
#if CPU(ARM_THUMB2)
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
static const RegisterID EngineRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
static const RegisterID EngineRegister = JSC::ARMRegisters::r7;
#endif
static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
static const FPRegisterID FPScratchRegister = JSC::ARMRegisters::d1;
static const RegisterID Arg0Reg = JSC::ARMRegisters::r0;
static const RegisterID Arg1Reg = JSC::ARMRegisters::r1;
static const RegisterID Arg2Reg = JSC::ARMRegisters::r2;
static const RegisterID Arg3Reg = JSC::ARMRegisters::r3;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 4;
void popValue()
{
addPtr(TrustedImm32(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(JSC::ARMRegisters::lr);
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
push(TrustedImm32(0)); // exceptionHandler
push(AccumulatorRegisterValue);
push(AccumulatorRegisterTag);
push(addressTempRegister);
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
subPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
if (!tailCall) { // do not overwrite arg0 and arg1 (used in the tail call)
move(AccumulatorRegisterValue, ReturnValueRegisterValue);
move(AccumulatorRegisterTag, ReturnValueRegisterTag);
}
addPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(addressTempRegister);
pop(AccumulatorRegisterTag);
pop(AccumulatorRegisterValue);
pop(); // exceptionHandler
pop(FramePointerRegister);
pop(JSC::ARMRegisters::lr);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), dataTempRegister);
call(dataTempRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), dataTempRegister);
jump(dataTempRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_ARM32 PlatformAssemblerBase;
#endif
class PlatformAssemblerCommon : public JIT::PlatformAssemblerBase
{
public:
PlatformAssemblerCommon(const Value *constantTable)
: constantTable(constantTable)
{}
virtual ~PlatformAssemblerCommon();
Address exceptionHandlerAddress() const
{
return Address(FramePointerRegister, -1 * PointerSize);
}
Address contextAddress() const
{
return Address(JSStackFrameRegister, offsetof(CallData, context));
}
RegisterID registerForArg(int arg) const
{
Q_ASSERT(arg >= 0);
Q_ASSERT(arg < ArgInRegCount);
switch (arg) {
case 0: return Arg0Reg;
case 1: return Arg1Reg;
case 2: return Arg2Reg;
case 3: return Arg3Reg;
case 4: return Arg4Reg;
case 5: return Arg5Reg;
case 6: return Arg6Reg;
case 7: return Arg7Reg;
default:
Q_UNIMPLEMENTED();
Q_UNREACHABLE();
}
}
Address loadFunctionPtr(RegisterID target)
{
Address addr(CppStackFrameRegister, offsetof(JSTypesStackFrame, v4Function));
loadPtr(addr, target);
return Address(target);
}
Address loadCompilationUnitPtr(RegisterID target)
{
Address addr = loadFunctionPtr(target);
addr.offset = offsetof(QV4::FunctionData, compilationUnit);
loadPtr(addr, target);
return Address(target);
}
Address loadConstAddress(int constIndex, RegisterID baseReg = ScratchRegister)
{
Address addr = loadCompilationUnitPtr(baseReg);
addr.offset = offsetof(QV4::CompilationUnitRuntimeData, constants);
loadPtr(addr, baseReg);
addr.offset = constIndex * int(sizeof(QV4::Value));
return addr;
}
Address loadStringAddress(int stringId)
{
Address addr = loadCompilationUnitPtr(ScratchRegister);
addr.offset = offsetof(QV4::CompilationUnitRuntimeData, runtimeStrings);
loadPtr(addr, ScratchRegister);
return Address(ScratchRegister, stringId * PointerSize);
}
void passAsArg(RegisterID src, int arg)
{
move(src, registerForArg(arg));
}
void generateCatchTrampoline(std::function<void()> loadUndefined)
{
for (Jump j : catchyJumps)
j.link(this);
loadUndefined();
// We don't need to check for isInterrupted here because if that is set,
// then the first checkException() in any exception handler will find another "exception"
// and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
jump(ScratchRegister);
exitFunction.link(this);
if (functionExit.isSet())
jump(functionExit);
else
generateFunctionExit();
}
void checkException()
{
// This actually reads 4 bytes, starting at hasException.
// Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
addCatchyJump(
branch32(NotEqual,
Address(EngineRegister, offsetof(EngineBase, hasException)),
TrustedImm32(0)));
}
void addCatchyJump(Jump j)
{
Q_ASSERT(j.isSet());
catchyJumps.push_back(j);
}
void generateFunctionEntry()
{
generatePlatformFunctionEntry();
loadPtr(Address(CppStackFrameRegister, offsetof(JSTypesStackFrame, jsFrame)),
JSStackFrameRegister);
allocateStackSpace();
}
virtual void allocateStackSpace() {}
void generateFunctionExit()
{
if (functionExit.isSet()) {
jump(functionExit);
return;
}
functionExit = label();
freeStackSpace();
generatePlatformFunctionExit();
}
virtual void freeStackSpace() {}
void addLabelForOffset(int offset)
{
if (!labelForOffset.contains(offset))
labelForOffset.insert(offset, label());
}
void addJumpToOffset(const Jump &jump, int offset)
{
jumpsToLink.push_back({ jump, offset });
}
void addEHTarget(const DataLabelPtr &label, int offset)
{
ehTargets.push_back({ label, offset });
}
void link(Function *function, const char *jitKind);
Value constant(int idx) const
{ return constantTable[idx]; }
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
void storeInstructionPointer(int instructionOffset);
void passAccumulatorAsArg(int arg);
void pushAccumulatorAsArg(int arg);
void passFunctionAsArg(int arg);
void passEngineAsArg(int arg);
void passJSSlotAsArg(int reg, int arg);
void passAddressAsArg(Address addr, int arg);
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
void callRuntime(const void *funcPtr, const char *functionName = nullptr);
void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
void setTailCallArg(RegisterID src, int arg);
Address jsAlloca(int slotCount);
void storeInt32AsValue(int srcInt, Address destAddr);
private:
void passAccumulatorAsArg_internal(int arg, bool doPush);
static Address argStackAddress(int arg);
private:
const Value* constantTable;
struct JumpTarget { JSC::MacroAssemblerBase::Jump jump; int offset; };
std::vector<JumpTarget> jumpsToLink;
struct ExceptionHanlderTarget { JSC::MacroAssemblerBase::DataLabelPtr label; int offset; };
std::vector<ExceptionHanlderTarget> ehTargets;
QHash<int, JSC::MacroAssemblerBase::Label> labelForOffset;
QHash<const void *, const char *> functions;
std::vector<Jump> catchyJumps;
Label functionExit;
#ifndef QT_NO_DEBUG
enum { NoCall = -1 };
int remainingArgcForCall = NoCall;
#endif
int argcOnStackForCall = 0;
};
} // JIT namespace
} // QV4 namespace
QT_END_NAMESPACE
#endif // QT_CONFIG(qml_jit)
#endif // QV4PLATFORMASSEMBLER_P_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,153 @@
// Copyright (C) 2018 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
// Qt-Security score:significant
#ifndef QV4BASELINEASSEMBLER_P_H
#define QV4BASELINEASSEMBLER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qv4global_p.h>
#include <private/qv4function_p.h>
#include <QHash>
#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
#define GENERATE_RUNTIME_CALL(function, destination) \
callRuntime(reinterpret_cast<void *>(&Runtime::function::call), \
destination)
#define GENERATE_TAIL_CALL(function) \
tailCallRuntime(reinterpret_cast<void *>(&function))
class BaselineAssembler {
public:
BaselineAssembler(const Value* constantTable);
~BaselineAssembler();
// codegen infrastructure
void generatePrologue();
void generateEpilogue();
void link(Function *function);
void addLabel(int offset);
// loads/stores/moves
void loadConst(int constIndex);
void copyConst(int constIndex, int destReg);
void loadReg(int reg);
void moveReg(int sourceReg, int destReg);
void storeReg(int reg);
void loadLocal(int index, int level = 0);
void storeLocal(int index, int level = 0);
void loadString(int stringId);
void loadValue(ReturnedValue value);
void storeHeapObject(int reg);
void loadImport(int index);
// numeric ops
void unot();
void toNumber();
void uminus();
void ucompl();
void inc();
void dec();
void add(int lhs);
void bitAnd(int lhs);
void bitOr(int lhs);
void bitXor(int lhs);
void ushr(int lhs);
void shr(int lhs);
void shl(int lhs);
void bitAndConst(int rhs);
void bitOrConst(int rhs);
void bitXorConst(int rhs);
void ushrConst(int rhs);
void shrConst(int rhs);
void shlConst(int rhs);
void mul(int lhs);
void div(int lhs);
void mod(int lhs);
void sub(int lhs);
// comparissons
void cmpeqNull();
void cmpneNull();
void cmpeqInt(int lhs);
void cmpneInt(int lhs);
void cmpeq(int lhs);
void cmpne(int lhs);
void cmpgt(int lhs);
void cmpge(int lhs);
void cmplt(int lhs);
void cmple(int lhs);
void cmpStrictEqual(int lhs);
void cmpStrictNotEqual(int lhs);
// jumps
Q_REQUIRED_RESULT int jump(int offset);
Q_REQUIRED_RESULT int jumpTrue(int offset);
Q_REQUIRED_RESULT int jumpFalse(int offset);
Q_REQUIRED_RESULT int jumpNoException(int offset);
Q_REQUIRED_RESULT int jumpNotUndefined(int offset);
Q_REQUIRED_RESULT int jumpEqNull(int offset);
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
void storeInstructionPointer(int instructionOffset);
void passAccumulatorAsArg(int arg);
void passFunctionAsArg(int arg);
void passEngineAsArg(int arg);
void passJSSlotAsArg(int reg, int arg);
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
void callRuntime(const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
void loadAccumulatorFromFrame();
void jsTailCall(int func, int thisObject, int argc, int argv);
// exception/context stuff
void checkException();
void gotoCatchException();
void getException();
void setException();
Q_REQUIRED_RESULT int setUnwindHandler(int offset);
void clearUnwindHandler();
void unwindDispatch();
Q_REQUIRED_RESULT int unwindToLabel(int level, int offset);
void pushCatchContext(int index, int name);
void popContext();
void deadTemporalZoneCheck(int offsetForSavedIP, int variableName);
// other stuff
void ret();
protected:
void *d;
private:
typedef unsigned(*CmpFunc)(const Value&,const Value&);
void cmp(int cond, CmpFunc function, int lhs);
};
} // namespace JIT
} // namespace QV4
QT_END_NAMESPACE
#endif // QT_CONFIG(qml_jit)
#endif // QV4BASELINEASSEMBLER_P_H
@@ -0,0 +1,921 @@
// 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
// Qt-Security score:critical reason:jit
#include "qv4baselinejit_p.h"
#include "qv4baselineassembler_p.h"
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
#if QT_CONFIG(qml_jit)
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
using namespace QV4::Moth;
BaselineJIT::BaselineJIT(Function *function)
: function(function)
, as(new BaselineAssembler(&(function->compilationUnit->constants->asValue<Value>())))
{}
BaselineJIT::~BaselineJIT()
{}
void BaselineJIT::generate()
{
// qDebug()<<"jitting" << function->name()->toQString();
const char *code = function->codeData;
uint len = function->compiledFunction->codeSize;
for (unsigned i = 0, ei = function->compiledFunction->nLabelInfos; i != ei; ++i)
labels.insert(int(function->compiledFunction->labelInfoTable()[i]));
as->generatePrologue();
// Make sure the ACC register is initialized and not clobbered by the caller.
as->loadAccumulatorFromFrame();
decode(code, len);
as->generateEpilogue();
as->link(function);
// qDebug()<<"done";
}
#define STORE_IP() as->storeInstructionPointer(nextInstructionOffset())
#define STORE_ACC() as->saveAccumulatorInFrame()
#define LOAD_ACC() as->loadAccumulatorFromFrame()
#define BASELINEJIT_GENERATE_RUNTIME_CALL(function, destination) { \
as->GENERATE_RUNTIME_CALL(function, destination); \
if (Runtime::function::throws) \
as->checkException(); \
else {} } // this else prevents else statements after the macro from attaching to the if above
void BaselineJIT::generate_Ret()
{
as->ret();
}
void BaselineJIT::generate_Debug() { Q_UNREACHABLE(); }
void BaselineJIT::generate_LoadConst(int index)
{
as->loadConst(index);
}
void BaselineJIT::generate_LoadZero()
{
as->loadValue(Encode(int(0)));
}
void BaselineJIT::generate_LoadTrue()
{
as->loadValue(Encode(true));
}
void BaselineJIT::generate_LoadFalse()
{
as->loadValue(Encode(false));
}
void BaselineJIT::generate_LoadNull()
{
as->loadValue(Encode::null());
}
void BaselineJIT::generate_LoadUndefined()
{
as->loadValue(Encode::undefined());
}
void BaselineJIT::generate_LoadInt(int value)
{
//###
as->loadValue(Encode(value));
}
void BaselineJIT::generate_MoveConst(int constIndex, int destTemp)
{
as->copyConst(constIndex, destTemp);
}
void BaselineJIT::generate_LoadReg(int reg)
{
as->loadReg(reg);
}
void BaselineJIT::generate_StoreReg(int reg)
{
as->storeReg(reg);
}
void BaselineJIT::generate_MoveReg(int srcReg, int destReg)
{
// Don't clobber the accumulator.
as->moveReg(srcReg, destReg);
}
void BaselineJIT::generate_LoadImport(int index)
{
as->loadImport(index);
}
void BaselineJIT::generate_LoadLocal(int index)
{
as->loadLocal(index);
}
void BaselineJIT::generate_StoreLocal(int index)
{
as->checkException();
as->storeLocal(index);
}
void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
{
as->loadLocal(index, scope);
}
void BaselineJIT::generate_StoreScopedLocal(int scope, int index)
{
as->checkException();
as->storeLocal(index, scope);
}
void BaselineJIT::generate_LoadRuntimeString(int stringId)
{
as->loadString(stringId);
}
void BaselineJIT::generate_MoveRegExp(int regExpId, int destReg)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(regExpId, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(RegexpLiteral, CallResultDestination::InAccumulator);
as->storeReg(destReg);
}
void BaselineJIT::generate_LoadClosure(int value)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(value, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Closure, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_LoadName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_LoadGlobalLookup(int index)
{
STORE_IP();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
as->passFunctionAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
STORE_IP();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreNameSloppy(int name)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameSloppy, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_StoreNameStrict(int name)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameStrict, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadElement, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreElement(int base, int index)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passAccumulatorAsArg(3);
as->passJSSlotAsArg(index, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreElement, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(name, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_LoadOptionalProperty(int name, int offset)
{
labels.insert(as->jumpEqNull(absoluteOffset(offset)));
generate_LoadProperty(name);
}
void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(index, 3);
as->passAccumulatorAsArg(2);
as->passFunctionAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(GetLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_GetOptionalLookup(int index, int offset)
{
labels.insert(as->jumpEqNull(absoluteOffset(offset)));
generate_GetLookup(index);
}
void BaselineJIT::generate_StoreProperty(int name, int base)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passAccumulatorAsArg(3);
as->passInt32AsArg(name, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreProperty, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_SetLookup(int index, int base)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(4);
as->passAccumulatorAsArg(3);
as->passInt32AsArg(index, 2);
as->passJSSlotAsArg(base, 1);
as->passFunctionAsArg(0);
if (function->isStrict())
BASELINEJIT_GENERATE_RUNTIME_CALL(SetLookupStrict, CallResultDestination::InAccumulator)
else
BASELINEJIT_GENERATE_RUNTIME_CALL(SetLookupSloppy, CallResultDestination::InAccumulator)
}
void BaselineJIT::generate_LoadSuperProperty(int property)
{
STORE_IP();
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(property, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadSuperProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_StoreSuperProperty(int property)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(property, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreSuperProperty, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_Yield()
{
// #####
Q_UNREACHABLE();
}
void BaselineJIT::generate_YieldStar()
{
// #####
Q_UNREACHABLE();
}
void BaselineJIT::generate_Resume(int)
{
// #####
Q_UNREACHABLE();
}
void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(argc, 3);
as->passJSSlotAsArg(argv, 2);
as->passJSSlotAsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallValue, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passJSSlotAsArg(thisObject, 2);
as->passJSSlotAsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithReceiver, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passInt32AsArg(name, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passInt32AsArg(lookupIndex, 2);
as->passJSSlotAsArg(base, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(argc, 3);
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(argc, 2);
as->passJSSlotAsArg(argv, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPossiblyDirectEval, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(argc, 3);
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
as->passInt32AsArg(argc, 3);
as->passJSSlotAsArg(argv, 2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passJSSlotAsArg(thisObject, 2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithSpread, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TailCall(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->jsTailCall(func, thisObject, argc, argv);
}
void BaselineJIT::generate_Construct(int func, int argc, int argv)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Construct, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ConstructWithSpread(int func, int argc, int argv)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(5);
as->passInt32AsArg(argc, 4);
as->passJSSlotAsArg(argv, 3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(func, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ConstructWithSpread, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_SetUnwindHandler(int offset)
{
if (offset)
labels.insert(as->setUnwindHandler(absoluteOffset(offset)));
else
as->clearUnwindHandler();
}
void BaselineJIT::generate_UnwindDispatch()
{
as->unwindDispatch();
}
void BaselineJIT::generate_UnwindToLabel(int level, int offset)
{
labels.insert(as->unwindToLabel(level, absoluteOffset(offset)));
}
void BaselineJIT::generate_DeadTemporalZoneCheck(int name)
{
as->deadTemporalZoneCheck(nextInstructionOffset(), name);
}
void BaselineJIT::generate_ThrowException()
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
// LOAD_ACC(); <- not needed here since it would be unreachable.
}
void BaselineJIT::generate_GetException() { as->getException(); }
void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
STORE_ACC();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
void BaselineJIT::generate_PushWithContext()
{
STORE_IP();
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(CallData::Accumulator, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushWithContext, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_PushBlockContext(int index)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushBlockContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_CloneBlockContext()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CloneBlockContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PushScriptContext(int index)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushScriptContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PopScriptContext()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PopScriptContext, CallResultDestination::Ignore);
as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PopContext() { as->popContext(); }
void BaselineJIT::generate_GetIterator(int iterator)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(iterator, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(GetIterator, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_IteratorNext(int value, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(3);
as->passJSSlotAsArg(value, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNext, CallResultDestination::InAccumulator);
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(4);
as->passJSSlotAsArg(object, 3);
as->passJSSlotAsArg(iterator, 2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNextForYieldStar, CallResultDestination::InAccumulator);
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
void BaselineJIT::generate_IteratorClose()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorClose, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DestructureRestElement()
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(DestructureRestElement, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeleteProperty(int base, int index)
{
STORE_IP();
as->prepareCallWithArgCount(4);
as->passJSSlotAsArg(index, 3);
as->passJSSlotAsArg(base, 2);
as->passFunctionAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(DeleteProperty, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeleteName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(name, 2);
as->passFunctionAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(DeleteName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TypeofName(int name)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(name, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(TypeofName, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_TypeofValue()
{
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(TypeofValue, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DeclareVar(int varName, int isDeletable)
{
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(varName, 2);
as->passInt32AsArg(isDeletable, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(DeclareVar, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_DefineArray(int argc, int args)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(argc, 2);
as->passJSSlotAsArg(args, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ArrayLiteral, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
{
as->prepareCallWithArgCount(4);
as->passInt32AsArg(argc, 3);
as->passJSSlotAsArg(args, 2);
as->passInt32AsArg(internalClassId, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ObjectLiteral, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateClass(int classIndex, int heritage, int computedNames)
{
as->prepareCallWithArgCount(4);
as->passJSSlotAsArg(computedNames, 3);
as->passJSSlotAsArg(heritage, 2);
as->passInt32AsArg(classIndex, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CreateClass, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateMappedArgumentsObject()
{
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CreateMappedArgumentsObject,
CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateUnmappedArgumentsObject()
{
as->prepareCallWithArgCount(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CreateUnmappedArgumentsObject,
CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CreateRestParameter(int argIndex)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(argIndex, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(CreateRestParameter, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ConvertThisToObject()
{
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(CallData::This, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ConvertThisToObject, CallResultDestination::InAccumulator);
as->storeReg(CallData::This);
LOAD_ACC();
}
void BaselineJIT::generate_LoadSuperConstructor()
{
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(CallData::Function, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadSuperConstructor, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_ToObject()
{
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ToObject, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_Jump(int offset)
{
labels.insert(as->jump(absoluteOffset(offset)));
}
void BaselineJIT::generate_JumpTrue(int offset)
{
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
void BaselineJIT::generate_JumpFalse(int offset)
{
labels.insert(as->jumpFalse(absoluteOffset(offset)));
}
void BaselineJIT::generate_JumpNoException(int offset)
{
labels.insert(as->jumpNoException(absoluteOffset(offset)));
}
void BaselineJIT::generate_JumpNotUndefined(int offset)
{
labels.insert(as->jumpNotUndefined(absoluteOffset(offset)));
}
void BaselineJIT::generate_CheckException()
{
as->checkException();
}
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
void BaselineJIT::generate_CmpEqInt(int lhs) { as->cmpeqInt(lhs); }
void BaselineJIT::generate_CmpNeInt(int lhs) { as->cmpneInt(lhs); }
void BaselineJIT::generate_CmpEq(int lhs) { as->cmpeq(lhs); }
void BaselineJIT::generate_CmpNe(int lhs) { as->cmpne(lhs); }
void BaselineJIT::generate_CmpGt(int lhs) { as->cmpgt(lhs); }
void BaselineJIT::generate_CmpGe(int lhs) { as->cmpge(lhs); }
void BaselineJIT::generate_CmpLt(int lhs) { as->cmplt(lhs); }
void BaselineJIT::generate_CmpLe(int lhs) { as->cmple(lhs); }
void BaselineJIT::generate_CmpStrictEqual(int lhs) { as->cmpStrictEqual(lhs); }
void BaselineJIT::generate_CmpStrictNotEqual(int lhs) { as->cmpStrictNotEqual(lhs); }
void BaselineJIT::generate_CmpIn(int lhs)
{
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(lhs, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(In, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_CmpInstanceOf(int lhs)
{
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(lhs, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Instanceof, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_As(int lhs)
{
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
as->passJSSlotAsArg(lhs, 1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(As, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_UNot() { as->unot(); }
void BaselineJIT::generate_UPlus() { as->toNumber(); }
void BaselineJIT::generate_UMinus() { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
void BaselineJIT::generate_Increment() { as->inc(); }
void BaselineJIT::generate_Decrement() { as->dec(); }
void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
void BaselineJIT::generate_BitXor(int lhs) { as->bitXor(lhs); }
void BaselineJIT::generate_UShr(int lhs) { as->ushr(lhs); }
void BaselineJIT::generate_Shr(int lhs) { as->shr(lhs); }
void BaselineJIT::generate_Shl(int lhs) { as->shl(lhs); }
void BaselineJIT::generate_BitAndConst(int rhs) { as->bitAndConst(rhs); }
void BaselineJIT::generate_BitOrConst(int rhs) { as->bitOrConst(rhs); }
void BaselineJIT::generate_BitXorConst(int rhs) { as->bitXorConst(rhs); }
void BaselineJIT::generate_UShrConst(int rhs) { as->ushrConst(rhs); }
void BaselineJIT::generate_ShrConst(int rhs) { as->shrConst(rhs); }
void BaselineJIT::generate_ShlConst(int rhs) { as->shlConst(rhs); }
void BaselineJIT::generate_Exp(int lhs) {
STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passJSSlotAsArg(lhs, 0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Exp, CallResultDestination::InAccumulator);
}
void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
// auto engine = function->internalClass->engine;
// void *op = engine->runtime.runtimeMethods[alu];
// STORE_ACC();
// as->passAccumulatorAsArg(2);
// as->passRegAsArg(lhs, 1);
// as->passEngineAsArg(0);
// as->callRuntime("binopContext", op, CallResultDestination::InAccumulator);
// as->checkException();
//}
void BaselineJIT::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
{
as->loadValue(Value::emptyValue().rawValue());
for (int i = firstReg, end = firstReg + count; i < end; ++i)
as->storeReg(i);
}
void BaselineJIT::generate_ThrowOnNullOrUndefined()
{
STORE_ACC();
as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowOnNullOrUndefined, CallResultDestination::Ignore);
LOAD_ACC();
}
void BaselineJIT::generate_GetTemplateObject(int index)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passFunctionAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(GetTemplateObject, CallResultDestination::InAccumulator);
}
ByteCodeHandler::Verdict BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
if (labels.contains(currentInstructionOffset()))
as->addLabel(currentInstructionOffset());
return ProcessInstruction;
}
void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
#endif // QT_CONFIG(qml_jit)
@@ -0,0 +1,193 @@
// 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
// Qt-Security score:significant
#ifndef QV4JIT_P_H
#define QV4JIT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qv4global_p.h>
#include <private/qv4function_p.h>
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
#include <QtCore/qset.h>
#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
class BaselineAssembler;
class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
Q_AUTOTEST_EXPORT BaselineJIT(QV4::Function *);
Q_AUTOTEST_EXPORT ~BaselineJIT() override;
Q_AUTOTEST_EXPORT void generate();
void generate_Ret() override;
void generate_Debug() override;
void generate_LoadConst(int index) override;
void generate_LoadZero() override;
void generate_LoadTrue() override;
void generate_LoadFalse() override;
void generate_LoadNull() override;
void generate_LoadUndefined() override;
void generate_LoadInt(int value) override;
void generate_MoveConst(int constIndex, int destTemp) override;
void generate_LoadReg(int reg) override;
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
void generate_LoadLocal(int index) override;
void generate_StoreLocal(int index) override;
void generate_LoadScopedLocal(int scope, int index) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
void generate_LoadName(int name) override;
void generate_LoadGlobalLookup(int index) override;
void generate_LoadQmlContextPropertyLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
void generate_LoadElement(int base) override;
void generate_StoreElement(int base, int index) override;
void generate_LoadProperty(int name) override;
void generate_LoadOptionalProperty(int name, int offset) override;
void generate_GetLookup(int index) override;
void generate_GetOptionalLookup(int index, int offset) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
void generate_StoreSuperProperty(int property) override;
void generate_Yield() override;
void generate_YieldStar() override;
void generate_Resume(int) override;
void generate_CallValue(int name, int argc, int argv) override;
void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
void generate_CallProperty(int name, int base, int argc, int argv) override;
void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
void generate_CallName(int name, int argc, int argv) override;
void generate_CallPossiblyDirectEval(int argc, int argv) override;
void generate_CallGlobalLookup(int index, int argc, int argv) override;
void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
void generate_SetUnwindHandler(int offset) override;
void generate_UnwindDispatch() override;
void generate_UnwindToLabel(int level, int offset) override;
void generate_DeadTemporalZoneCheck(int name) override;
void generate_ThrowException() override;
void generate_GetException() override;
void generate_SetException() override;
void generate_CreateCallContext() override;
void generate_PushCatchContext(int index, int name) override;
void generate_PushWithContext() override;
void generate_PushBlockContext(int index) override;
void generate_CloneBlockContext() override;
void generate_PushScriptContext(int index) override;
void generate_PopScriptContext() override;
void generate_PopContext() override;
void generate_GetIterator(int iterator) override;
void generate_IteratorNext(int value, int offset) override;
void generate_IteratorNextForYieldStar(int iterator, int object, int offset) override;
void generate_IteratorClose() override;
void generate_DestructureRestElement() override;
void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;
void generate_TypeofName(int name) override;
void generate_TypeofValue() override;
void generate_DeclareVar(int varName, int isDeletable) override;
void generate_DefineArray(int argc, int args) override;
void generate_DefineObjectLiteral(int internalClassId, int argc, int args) override;
void generate_CreateClass(int classIndex, int heritage, int computedNames) override;
void generate_CreateMappedArgumentsObject() override;
void generate_CreateUnmappedArgumentsObject() override;
void generate_CreateRestParameter(int argIndex) override;
void generate_ConvertThisToObject() override;
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
void generate_JumpTrue(int offset) override;
void generate_JumpFalse(int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
void generate_CheckException() override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
void generate_CmpNeInt(int lhs) override;
void generate_CmpEq(int lhs) override;
void generate_CmpNe(int lhs) override;
void generate_CmpGt(int lhs) override;
void generate_CmpGe(int lhs) override;
void generate_CmpLt(int lhs) override;
void generate_CmpLe(int lhs) override;
void generate_CmpStrictEqual(int lhs) override;
void generate_CmpStrictNotEqual(int lhs) override;
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
void generate_As(int lhs) override;
void generate_UNot() override;
void generate_UPlus() override;
void generate_UMinus() override;
void generate_UCompl() override;
void generate_Increment() override;
void generate_Decrement() override;
void generate_Add(int lhs) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
void generate_UShr(int lhs) override;
void generate_Shr(int lhs) override;
void generate_Shl(int lhs) override;
void generate_BitAndConst(int rhs) override;
void generate_BitOrConst(int rhs) override;
void generate_BitXorConst(int rhs) override;
void generate_UShrConst(int rhs) override;
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
void generate_Mod(int lhs) override;
void generate_Sub(int lhs) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
Verdict startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
private:
QV4::Function *function;
QScopedPointer<BaselineAssembler> as;
QSet<int> labels;
};
} // namespace JIT
} // namespace QV4
QT_END_NAMESPACE
#endif // QT_CONFIG(qml_jit)
#endif // QV4JIT_P_H