#include "config.h"
#include "FTLLink.h"
#if ENABLE(FTL_JIT)
#include "CCallHelpers.h"
#include "CodeBlockWithJITType.h"
#include "DFGCommon.h"
#include "FTLJITCode.h"
#include "JITOperations.h"
#include "LinkBuffer.h"
#include "JSCInlines.h"
#include "ProfilerCompilation.h"
#include "ThunkGenerators.h"
#include "VirtualRegister.h"
namespace JSC { namespace FTL {
using namespace DFG;
void link(State& state)
{
Graph& graph = state.graph;
CodeBlock* codeBlock = graph.m_codeBlock;
VM& vm = graph.m_vm;
codeBlock->clearSwitchJumpTables();
state.jitCode->common.requiredRegisterCountForExit = graph.requiredRegisterCountForExit();
if (!graph.m_plan.inlineCallFrames->isEmpty())
state.jitCode->common.inlineCallFrames = graph.m_plan.inlineCallFrames;
graph.registerFrozenValues();
CCallHelpers jit(codeBlock);
std::unique_ptr<LinkBuffer> linkBuffer;
CCallHelpers::Address frame = CCallHelpers::Address(
CCallHelpers::stackPointerRegister, -static_cast<int32_t>(AssemblyHelpers::prologueStackPointerDelta()));
if (Profiler::Compilation* compilation = graph.compilation()) {
compilation->addDescription(
Profiler::OriginStack(),
toCString("Generated FTL JIT code for ", CodeBlockWithJITType(codeBlock, JITCode::FTLJIT), ", instruction count = ", graph.m_codeBlock->instructionCount(), ":\n"));
graph.ensureDominators();
graph.ensureNaturalLoops();
const char* prefix = " ";
DumpContext dumpContext;
StringPrintStream out;
Node* lastNode = 0;
for (size_t blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) {
BasicBlock* block = graph.block(blockIndex);
if (!block)
continue;
graph.dumpBlockHeader(out, prefix, block, Graph::DumpLivePhisOnly, &dumpContext);
compilation->addDescription(Profiler::OriginStack(), out.toCString());
out.reset();
for (size_t nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
Node* node = block->at(nodeIndex);
Profiler::OriginStack stack;
if (node->origin.semantic.isSet()) {
stack = Profiler::OriginStack(
*vm.m_perBytecodeProfiler, codeBlock, node->origin.semantic);
}
if (graph.dumpCodeOrigin(out, prefix, lastNode, node, &dumpContext)) {
compilation->addDescription(stack, out.toCString());
out.reset();
}
graph.dump(out, prefix, node, &dumpContext);
compilation->addDescription(stack, out.toCString());
out.reset();
if (node->origin.semantic.isSet())
lastNode = node;
}
}
dumpContext.dump(out, prefix);
compilation->addDescription(Profiler::OriginStack(), out.toCString());
out.reset();
out.print(" Disassembly:\n");
out.print(" <not implemented yet>\n");
compilation->addDescription(Profiler::OriginStack(), out.toCString());
out.reset();
state.jitCode->common.compilation = compilation;
}
switch (graph.m_plan.mode) {
case FTLMode: {
if (codeBlock->codeType() == FunctionCode) {
CCallHelpers::JumpList mainPathJumps;
jit.load32(
frame.withOffset(sizeof(Register) * CallFrameSlot::argumentCount),
GPRInfo::regT1);
mainPathJumps.append(jit.branch32(
CCallHelpers::AboveOrEqual, GPRInfo::regT1,
CCallHelpers::TrustedImm32(codeBlock->numParameters())));
jit.emitFunctionPrologue();
jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
jit.storePtr(GPRInfo::callFrameRegister, &vm.topCallFrame);
CCallHelpers::Call callArityCheck = jit.call();
auto noException = jit.branch32(CCallHelpers::GreaterThanOrEqual, GPRInfo::returnValueGPR, CCallHelpers::TrustedImm32(0));
jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(vm);
jit.move(CCallHelpers::TrustedImmPtr(&vm), GPRInfo::argumentGPR0);
jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
CCallHelpers::Call callLookupExceptionHandlerFromCallerFrame = jit.call();
jit.jumpToExceptionHandler(vm);
noException.link(&jit);
if (!ASSERT_DISABLED) {
jit.load64(vm.addressOfException(), GPRInfo::regT1);
jit.jitAssertIsNull(GPRInfo::regT1);
}
jit.move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
jit.emitFunctionEpilogue();
mainPathJumps.append(jit.branchTest32(CCallHelpers::Zero, GPRInfo::argumentGPR0));
jit.emitFunctionPrologue();
CCallHelpers::Call callArityFixup = jit.call();
jit.emitFunctionEpilogue();
mainPathJumps.append(jit.jump());
linkBuffer = std::make_unique<LinkBuffer>(jit, codeBlock, JITCompilationCanFail);
if (linkBuffer->didFailToAllocate()) {
state.allocationFailed = true;
return;
}
linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck);
linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, lookupExceptionHandlerFromCallerFrame);
linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress()));
linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
}
state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction)));
break;
}
case FTLForOSREntryMode: {
CCallHelpers::Label start = jit.label();
jit.emitFunctionEpilogue();
CCallHelpers::Jump mainPathJump = jit.jump();
linkBuffer = std::make_unique<LinkBuffer>(jit, codeBlock, JITCompilationCanFail);
if (linkBuffer->didFailToAllocate()) {
state.allocationFailed = true;
return;
}
linkBuffer->link(mainPathJump, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction)));
state.jitCode->initializeAddressForCall(linkBuffer->locationOf(start));
break;
}
default:
RELEASE_ASSERT_NOT_REACHED();
break;
}
state.finalizer->entrypointLinkBuffer = WTFMove(linkBuffer);
state.finalizer->function = state.generatedFunction;
state.finalizer->jitCode = state.jitCode;
}
} }
#endif // ENABLE(FTL_JIT)