summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/ftl/FTLCompile.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-05-20 09:56:07 +0000
commit41386e9cb918eed93b3f13648cbef387e371e451 (patch)
treea97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/ftl/FTLCompile.cpp
parente15dd966d523731101f70ccf768bba12435a0208 (diff)
downloadWebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLCompile.cpp')
-rw-r--r--Source/JavaScriptCore/ftl/FTLCompile.cpp819
1 files changed, 187 insertions, 632 deletions
diff --git a/Source/JavaScriptCore/ftl/FTLCompile.cpp b/Source/JavaScriptCore/ftl/FTLCompile.cpp
index c6fcca05e..6c01f4fa5 100644
--- a/Source/JavaScriptCore/ftl/FTLCompile.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCompile.cpp
@@ -1,7 +1,5 @@
/*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
- * Copyright (C) 2014 Samsung Electronics
- * Copyright (C) 2014 University of Szeged
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,14 +31,12 @@
#include "CodeBlockWithJITType.h"
#include "CCallHelpers.h"
#include "DFGCommon.h"
-#include "DFGGraphSafepoint.h"
#include "DataView.h"
#include "Disassembler.h"
#include "FTLExitThunkGenerator.h"
#include "FTLInlineCacheSize.h"
#include "FTLJITCode.h"
#include "FTLThunks.h"
-#include "FTLUnwindInfo.h"
#include "JITStubs.h"
#include "LLVMAPI.h"
#include "LinkBuffer.h"
@@ -53,30 +49,14 @@ using namespace DFG;
static uint8_t* mmAllocateCodeSection(
void* opaqueState, uintptr_t size, unsigned alignment, unsigned, const char* sectionName)
{
+
State& state = *static_cast<State*>(opaqueState);
RELEASE_ASSERT(alignment <= jitAllocationGranule);
RefPtr<ExecutableMemoryHandle> result =
state.graph.m_vm.executableAllocator.allocate(
- state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationCanFail);
-
- if (!result) {
- // Signal failure. This compilation will get tossed.
- state.allocationFailed = true;
-
- // Fake an allocation, since LLVM cannot handle failures in the memory manager.
- RefPtr<DataSection> fakeSection = adoptRef(new DataSection(size, jitAllocationGranule));
- state.jitCode->addDataSection(fakeSection);
- return bitwise_cast<uint8_t*>(fakeSection->base());
- }
-
- // LLVM used to put __compact_unwind in a code section. We keep this here defensively,
- // for clients that use older LLVMs.
- if (!strcmp(sectionName, SECTION_NAME("compact_unwind"))) {
- state.unwindDataSection = result->start();
- state.unwindDataSectionSize = result->sizeInBytes();
- }
+ state.graph.m_vm, size, state.graph.m_codeBlock, JITCompilationMustSucceed);
state.jitCode->addHandle(result);
state.codeSectionNames.append(sectionName);
@@ -91,32 +71,21 @@ static uint8_t* mmAllocateDataSection(
UNUSED_PARAM(sectionID);
UNUSED_PARAM(isReadOnly);
- // Allocate the GOT in the code section to make it reachable for all code.
- if (!strcmp(sectionName, SECTION_NAME("got")))
- return mmAllocateCodeSection(opaqueState, size, alignment, sectionID, sectionName);
-
State& state = *static_cast<State*>(opaqueState);
-
- RefPtr<DataSection> section = adoptRef(new DataSection(size, alignment));
-
- if (!strcmp(sectionName, SECTION_NAME("llvm_stackmaps")))
+
+ RELEASE_ASSERT(alignment <= sizeof(LSectionWord));
+
+ RefCountedArray<LSectionWord> section(
+ (size + sizeof(LSectionWord) - 1) / sizeof(LSectionWord));
+
+ if (!strcmp(sectionName, "__llvm_stackmaps"))
state.stackmapsSection = section;
else {
state.jitCode->addDataSection(section);
state.dataSectionNames.append(sectionName);
-#if OS(DARWIN)
- if (!strcmp(sectionName, SECTION_NAME("compact_unwind"))) {
-#elif OS(LINUX)
- if (!strcmp(sectionName, SECTION_NAME("eh_frame"))) {
-#else
-#error "Unrecognized OS"
-#endif
- state.unwindDataSection = section->base();
- state.unwindDataSectionSize = size;
- }
}
-
- return bitwise_cast<uint8_t*>(section->base());
+
+ return bitwise_cast<uint8_t*>(section.data());
}
static LLVMBool mmApplyPermissions(void*, char**)
@@ -128,74 +97,13 @@ static void mmDestroy(void*)
{
}
-static void dumpDataSection(DataSection* section, const char* prefix)
+static void dumpDataSection(RefCountedArray<LSectionWord> section, const char* prefix)
{
- for (unsigned j = 0; j < section->size() / sizeof(int64_t); ++j) {
+ for (unsigned j = 0; j < section.size(); ++j) {
char buf[32];
- int64_t* wordPointer = static_cast<int64_t*>(section->base()) + j;
- snprintf(buf, sizeof(buf), "0x%lx", static_cast<unsigned long>(bitwise_cast<uintptr_t>(wordPointer)));
- dataLogF("%s%16s: 0x%016llx\n", prefix, buf, static_cast<long long>(*wordPointer));
- }
-}
-
-static int offsetOfStackRegion(StackMaps::RecordMap& recordMap, uint32_t stackmapID)
-{
- if (stackmapID == UINT_MAX)
- return 0;
-
- StackMaps::RecordMap::iterator iter = recordMap.find(stackmapID);
- RELEASE_ASSERT(iter != recordMap.end());
- RELEASE_ASSERT(iter->value.size() == 1);
- RELEASE_ASSERT(iter->value[0].locations.size() == 1);
- Location capturedLocation =
- Location::forStackmaps(nullptr, iter->value[0].locations[0]);
- RELEASE_ASSERT(capturedLocation.kind() == Location::Register);
- RELEASE_ASSERT(capturedLocation.gpr() == GPRInfo::callFrameRegister);
- RELEASE_ASSERT(!(capturedLocation.addend() % sizeof(Register)));
- return capturedLocation.addend() / sizeof(Register);
-}
-
-static void generateInlineIfPossibleOutOfLineIfNot(State& state, VM& vm, CodeBlock* codeBlock, CCallHelpers& code, char* startOfInlineCode, size_t sizeOfInlineCode, const char* codeDescription, const std::function<void(LinkBuffer&, CCallHelpers&, bool wasCompiledInline)>& callback)
-{
- std::unique_ptr<LinkBuffer> codeLinkBuffer;
- size_t actualCodeSize = code.m_assembler.buffer().codeSize();
-
- if (actualCodeSize <= sizeOfInlineCode) {
- LinkBuffer codeLinkBuffer(vm, code, startOfInlineCode, sizeOfInlineCode);
-
- // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
- MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + actualCodeSize, sizeOfInlineCode - actualCodeSize);
-
- callback(codeLinkBuffer, code, true);
-
- return;
+ snprintf(buf, sizeof(buf), "0x%lx", static_cast<unsigned long>(bitwise_cast<uintptr_t>(section.data() + j)));
+ dataLogF("%s%16s: 0x%016llx\n", prefix, buf, static_cast<long long>(section[j]));
}
-
- // If there isn't enough space in the provided inline code area, allocate out of line
- // executable memory to link the provided code. Place a jump at the beginning of the
- // inline area and jump to the out of line code. Similarly return by appending a jump
- // to the provided code that goes to the instruction after the inline code.
- // Fill the middle with nop's.
- MacroAssembler::Jump returnToMainline = code.jump();
-
- // Allocate out of line executable memory and link the provided code there.
- codeLinkBuffer = std::make_unique<LinkBuffer>(vm, code, codeBlock, JITCompilationMustSucceed);
-
- // Plant a jmp in the inline buffer to the out of line code.
- MacroAssembler callToOutOfLineCode;
- MacroAssembler::Jump jumpToOutOfLine = callToOutOfLineCode.jump();
- LinkBuffer inlineBuffer(vm, callToOutOfLineCode, startOfInlineCode, sizeOfInlineCode);
- inlineBuffer.link(jumpToOutOfLine, codeLinkBuffer->entrypoint());
-
- // Fill the remainder of the inline space with nops to avoid confusing the disassembler.
- MacroAssembler::AssemblerType_T::fillNops(bitwise_cast<char*>(startOfInlineCode) + inlineBuffer.size(), sizeOfInlineCode - inlineBuffer.size());
-
- // Link the end of the out of line code to right after the inline area.
- codeLinkBuffer->link(returnToMainline, CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(startOfInlineCode)).labelAtOffset(sizeOfInlineCode));
-
- callback(*codeLinkBuffer.get(), code, false);
-
- state.finalizer->outOfLineCodeInfos.append(OutOfLineCodeInfo(WTF::move(codeLinkBuffer), codeDescription));
}
template<typename DescriptorType>
@@ -211,360 +119,148 @@ void generateICFastPath(
return;
}
- Vector<StackMaps::Record>& records = iter->value;
-
- RELEASE_ASSERT(records.size() == ic.m_generators.size());
-
- for (unsigned i = records.size(); i--;) {
- StackMaps::Record& record = records[i];
- auto generator = ic.m_generators[i];
+ StackMaps::Record& record = iter->value;
- CCallHelpers fastPathJIT(&vm, codeBlock);
- generator.generateFastPath(fastPathJIT);
-
- char* startOfIC =
- bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
+ CCallHelpers fastPathJIT(&vm, codeBlock);
+ ic.m_generator.generateFastPath(fastPathJIT);
- generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "inline cache fast path", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
- state.finalizer->sideCodeLinkBuffer->link(ic.m_slowPathDone[i],
- CodeLocationLabel(startOfIC + sizeOfIC));
-
- linkBuffer.link(generator.slowPathJump(),
- state.finalizer->sideCodeLinkBuffer->locationOf(generator.slowPathBegin()));
-
- generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
- });
- }
-}
-
-static void generateCheckInICFastPath(
- State& state, CodeBlock* codeBlock, GeneratedFunction generatedFunction,
- StackMaps::RecordMap& recordMap, CheckInDescriptor& ic, size_t sizeOfIC)
-{
- VM& vm = state.graph.m_vm;
-
- StackMaps::RecordMap::iterator iter = recordMap.find(ic.stackmapID());
- if (iter == recordMap.end()) {
- // It was optimized out.
- return;
- }
-
- Vector<StackMaps::Record>& records = iter->value;
+ char* startOfIC =
+ bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
+
+ LinkBuffer linkBuffer(vm, &fastPathJIT, startOfIC, sizeOfIC);
+ // Note: we could handle the !isValid() case. We just don't appear to have a
+ // reason to do so, yet.
+ RELEASE_ASSERT(linkBuffer.isValid());
- RELEASE_ASSERT(records.size() == ic.m_generators.size());
-
- for (unsigned i = records.size(); i--;) {
- StackMaps::Record& record = records[i];
- auto generator = ic.m_generators[i];
-
- StructureStubInfo& stubInfo = *generator.m_stub;
- auto call = generator.m_slowCall;
- auto slowPathBegin = generator.m_beginLabel;
-
- CCallHelpers fastPathJIT(&vm, codeBlock);
-
- auto jump = fastPathJIT.patchableJump();
- auto done = fastPathJIT.label();
-
- char* startOfIC =
- bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
-
- auto postLink = [&] (LinkBuffer& fastPath, CCallHelpers&, bool) {
- LinkBuffer& slowPath = *state.finalizer->sideCodeLinkBuffer;
-
- state.finalizer->sideCodeLinkBuffer->link(
- ic.m_slowPathDone[i], CodeLocationLabel(startOfIC + sizeOfIC));
-
- CodeLocationLabel slowPathBeginLoc = slowPath.locationOf(slowPathBegin);
- fastPath.link(jump, slowPathBeginLoc);
-
- CodeLocationCall callReturnLocation = slowPath.locationOf(call);
-
- stubInfo.patch.deltaCallToDone = MacroAssembler::differenceBetweenCodePtr(
- callReturnLocation, fastPath.locationOf(done));
-
- stubInfo.patch.deltaCallToJump = MacroAssembler::differenceBetweenCodePtr(
- callReturnLocation, fastPath.locationOf(jump));
- stubInfo.callReturnLocation = callReturnLocation;
- stubInfo.patch.deltaCallToSlowCase = MacroAssembler::differenceBetweenCodePtr(
- callReturnLocation, slowPathBeginLoc);
- };
-
- generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "CheckIn inline cache", postLink);
- }
-}
-
-
-static RegisterSet usedRegistersFor(const StackMaps::Record& record)
-{
- if (Options::assumeAllRegsInFTLICAreLive())
- return RegisterSet::allRegisters();
- return RegisterSet(record.usedRegisterSet(), RegisterSet::calleeSaveRegisters());
-}
-
-template<typename CallType>
-void adjustCallICsForStackmaps(Vector<CallType>& calls, StackMaps::RecordMap& recordMap)
-{
- // Handling JS calls is weird: we need to ensure that we sort them by the PC in LLVM
- // generated code. That implies first pruning the ones that LLVM didn't generate.
-
- Vector<CallType> oldCalls;
- oldCalls.swap(calls);
+ MacroAssembler::AssemblerType_T::fillNops(
+ startOfIC + linkBuffer.size(), sizeOfIC - linkBuffer.size());
- for (unsigned i = 0; i < oldCalls.size(); ++i) {
- CallType& call = oldCalls[i];
-
- StackMaps::RecordMap::iterator iter = recordMap.find(call.stackmapID());
- if (iter == recordMap.end())
- continue;
-
- for (unsigned j = 0; j < iter->value.size(); ++j) {
- CallType copy = call;
- copy.m_instructionOffset = iter->value[j].instructionOffset;
- calls.append(copy);
- }
- }
-
- std::sort(calls.begin(), calls.end());
+ state.finalizer->sideCodeLinkBuffer->link(
+ ic.m_slowPathDone, CodeLocationLabel(startOfIC + sizeOfIC));
+
+ linkBuffer.link(
+ ic.m_generator.slowPathJump(),
+ state.finalizer->sideCodeLinkBuffer->locationOf(ic.m_generator.slowPathBegin()));
+
+ ic.m_generator.finalize(linkBuffer, *state.finalizer->sideCodeLinkBuffer);
}
static void fixFunctionBasedOnStackMaps(
State& state, CodeBlock* codeBlock, JITCode* jitCode, GeneratedFunction generatedFunction,
- StackMaps::RecordMap& recordMap, bool didSeeUnwindInfo)
+ StackMaps::RecordMap& recordMap)
{
- Graph& graph = state.graph;
- VM& vm = graph.m_vm;
+ VM& vm = state.graph.m_vm;
StackMaps stackmaps = jitCode->stackmaps;
-
- int localsOffset = offsetOfStackRegion(recordMap, state.capturedStackmapID) + graph.m_nextMachineLocal;
- int varargsSpillSlotsOffset = offsetOfStackRegion(recordMap, state.varargsSpillSlotsStackmapID);
-
- for (unsigned i = graph.m_inlineVariableData.size(); i--;) {
- InlineCallFrame* inlineCallFrame = graph.m_inlineVariableData[i].inlineCallFrame;
-
- if (inlineCallFrame->argumentCountRegister.isValid())
- inlineCallFrame->argumentCountRegister += localsOffset;
-
- for (unsigned argument = inlineCallFrame->arguments.size(); argument-- > 1;) {
- inlineCallFrame->arguments[argument] =
- inlineCallFrame->arguments[argument].withLocalsOffset(localsOffset);
- }
-
- if (inlineCallFrame->isClosureCall) {
- inlineCallFrame->calleeRecovery =
- inlineCallFrame->calleeRecovery.withLocalsOffset(localsOffset);
- }
-
- if (graph.hasDebuggerEnabled())
- codeBlock->setScopeRegister(codeBlock->scopeRegister() + localsOffset);
- }
-
- MacroAssembler::Label stackOverflowException;
-
- {
- CCallHelpers checkJIT(&vm, codeBlock);
-
- // At this point it's perfectly fair to just blow away all state and restore the
- // JS JIT view of the universe.
- checkJIT.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0);
- checkJIT.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
- MacroAssembler::Call callLookupExceptionHandler = checkJIT.call();
- checkJIT.jumpToExceptionHandler();
-
- stackOverflowException = checkJIT.label();
- checkJIT.move(MacroAssembler::TrustedImmPtr(&vm), GPRInfo::argumentGPR0);
- checkJIT.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
- MacroAssembler::Call callLookupExceptionHandlerFromCallerFrame = checkJIT.call();
- checkJIT.jumpToExceptionHandler();
-
- auto linkBuffer = std::make_unique<LinkBuffer>(
- vm, checkJIT, codeBlock, JITCompilationCanFail);
- if (linkBuffer->didFailToAllocate()) {
- state.allocationFailed = true;
- return;
- }
- linkBuffer->link(callLookupExceptionHandler, FunctionPtr(lookupExceptionHandler));
- linkBuffer->link(callLookupExceptionHandlerFromCallerFrame, FunctionPtr(lookupExceptionHandlerFromCallerFrame));
-
- state.finalizer->handleExceptionsLinkBuffer = WTF::move(linkBuffer);
- }
ExitThunkGenerator exitThunkGenerator(state);
exitThunkGenerator.emitThunks();
if (exitThunkGenerator.didThings()) {
- RELEASE_ASSERT(state.finalizer->osrExit.size());
- RELEASE_ASSERT(didSeeUnwindInfo);
+ OwnPtr<LinkBuffer> linkBuffer = adoptPtr(new LinkBuffer(
+ vm, &exitThunkGenerator, codeBlock, JITCompilationMustSucceed));
- auto linkBuffer = std::make_unique<LinkBuffer>(
- vm, exitThunkGenerator, codeBlock, JITCompilationCanFail);
- if (linkBuffer->didFailToAllocate()) {
- state.allocationFailed = true;
- return;
- }
-
- RELEASE_ASSERT(state.finalizer->osrExit.size() == state.jitCode->osrExit.size());
+ ASSERT(state.finalizer->osrExit.size() == state.jitCode->osrExit.size());
for (unsigned i = 0; i < state.jitCode->osrExit.size(); ++i) {
OSRExitCompilationInfo& info = state.finalizer->osrExit[i];
OSRExit& exit = jitCode->osrExit[i];
- if (verboseCompilationEnabled())
+ if (Options::verboseCompilation())
dataLog("Handling OSR stackmap #", exit.m_stackmapID, " for ", exit.m_codeOrigin, "\n");
-
- auto iter = recordMap.find(exit.m_stackmapID);
+
+ StackMaps::RecordMap::iterator iter = recordMap.find(exit.m_stackmapID);
if (iter == recordMap.end()) {
// It was optimized out.
continue;
}
info.m_thunkAddress = linkBuffer->locationOf(info.m_thunkLabel);
- exit.m_patchableCodeOffset = linkBuffer->offsetOf(info.m_thunkJump);
-
- for (unsigned j = exit.m_values.size(); j--;)
- exit.m_values[j] = exit.m_values[j].withLocalsOffset(localsOffset);
- for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
- materialization->accountForLocalsOffset(localsOffset);
- if (verboseCompilationEnabled()) {
- DumpContext context;
- dataLog(" Exit values: ", inContext(exit.m_values, &context), "\n");
- if (!exit.m_materializations.isEmpty()) {
- dataLog(" Materializations: \n");
- for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
- dataLog(" Materialize(", pointerDump(materialization), ")\n");
- }
- }
+ exit.m_patchableCodeOffset = linkBuffer->offsetOf(info.m_thunkJump);
}
- state.finalizer->exitThunksLinkBuffer = WTF::move(linkBuffer);
+ state.finalizer->exitThunksLinkBuffer = linkBuffer.release();
}
- if (!state.getByIds.isEmpty() || !state.putByIds.isEmpty() || !state.checkIns.isEmpty()) {
+ if (!state.getByIds.isEmpty() || !state.putByIds.isEmpty()) {
CCallHelpers slowPathJIT(&vm, codeBlock);
- CCallHelpers::JumpList exceptionTarget;
-
for (unsigned i = state.getByIds.size(); i--;) {
GetByIdDescriptor& getById = state.getByIds[i];
- if (verboseCompilationEnabled())
+ if (Options::verboseCompilation())
dataLog("Handling GetById stackmap #", getById.stackmapID(), "\n");
- auto iter = recordMap.find(getById.stackmapID());
+ StackMaps::RecordMap::iterator iter = recordMap.find(getById.stackmapID());
if (iter == recordMap.end()) {
// It was optimized out.
continue;
}
- for (unsigned i = 0; i < iter->value.size(); ++i) {
- StackMaps::Record& record = iter->value[i];
+ StackMaps::Record& record = iter->value;
- RegisterSet usedRegisters = usedRegistersFor(record);
-
- GPRReg result = record.locations[0].directGPR();
- GPRReg base = record.locations[1].directGPR();
-
- JITGetByIdGenerator gen(
- codeBlock, getById.codeOrigin(), usedRegisters, JSValueRegs(base),
- JSValueRegs(result), NeedToSpill);
-
- MacroAssembler::Label begin = slowPathJIT.label();
-
- MacroAssembler::Call call = callOperation(
- state, usedRegisters, slowPathJIT, getById.codeOrigin(), &exceptionTarget,
- operationGetByIdOptimize, result, gen.stubInfo(), base, getById.uid());
-
- gen.reportSlowPathCall(begin, call);
-
- getById.m_slowPathDone.append(slowPathJIT.jump());
- getById.m_generators.append(gen);
- }
+ // FIXME: LLVM should tell us which registers are live.
+ RegisterSet usedRegisters = RegisterSet::allRegisters();
+
+ GPRReg result = record.locations[0].directGPR();
+ GPRReg callFrameRegister = record.locations[1].directGPR();
+ GPRReg base = record.locations[2].directGPR();
+
+ JITGetByIdGenerator gen(
+ codeBlock, getById.codeOrigin(), usedRegisters, callFrameRegister,
+ JSValueRegs(base), JSValueRegs(result), false);
+
+ MacroAssembler::Label begin = slowPathJIT.label();
+
+ MacroAssembler::Call call = callOperation(
+ state, usedRegisters, slowPathJIT, operationGetByIdOptimize, result,
+ callFrameRegister, gen.stubInfo(), base, getById.uid());
+
+ gen.reportSlowPathCall(begin, call);
+
+ getById.m_slowPathDone = slowPathJIT.jump();
+ getById.m_generator = gen;
}
for (unsigned i = state.putByIds.size(); i--;) {
PutByIdDescriptor& putById = state.putByIds[i];
- if (verboseCompilationEnabled())
+ if (Options::verboseCompilation())
dataLog("Handling PutById stackmap #", putById.stackmapID(), "\n");
- auto iter = recordMap.find(putById.stackmapID());
+ StackMaps::RecordMap::iterator iter = recordMap.find(putById.stackmapID());
if (iter == recordMap.end()) {
// It was optimized out.
continue;
}
- for (unsigned i = 0; i < iter->value.size(); ++i) {
- StackMaps::Record& record = iter->value[i];
-
- RegisterSet usedRegisters = usedRegistersFor(record);
-
- GPRReg base = record.locations[0].directGPR();
- GPRReg value = record.locations[1].directGPR();
-
- JITPutByIdGenerator gen(
- codeBlock, putById.codeOrigin(), usedRegisters, JSValueRegs(base),
- JSValueRegs(value), GPRInfo::patchpointScratchRegister, NeedToSpill,
- putById.ecmaMode(), putById.putKind());
-
- MacroAssembler::Label begin = slowPathJIT.label();
-
- MacroAssembler::Call call = callOperation(
- state, usedRegisters, slowPathJIT, putById.codeOrigin(), &exceptionTarget,
- gen.slowPathFunction(), gen.stubInfo(), value, base, putById.uid());
-
- gen.reportSlowPathCall(begin, call);
-
- putById.m_slowPathDone.append(slowPathJIT.jump());
- putById.m_generators.append(gen);
- }
- }
-
- for (unsigned i = state.checkIns.size(); i--;) {
- CheckInDescriptor& checkIn = state.checkIns[i];
+ StackMaps::Record& record = iter->value;
- if (verboseCompilationEnabled())
- dataLog("Handling checkIn stackmap #", checkIn.stackmapID(), "\n");
+ // FIXME: LLVM should tell us which registers are live.
+ RegisterSet usedRegisters = RegisterSet::allRegisters();
- auto iter = recordMap.find(checkIn.stackmapID());
- if (iter == recordMap.end()) {
- // It was optimized out.
- continue;
- }
+ GPRReg callFrameRegister = record.locations[0].directGPR();
+ GPRReg base = record.locations[1].directGPR();
+ GPRReg value = record.locations[2].directGPR();
- for (unsigned i = 0; i < iter->value.size(); ++i) {
- StackMaps::Record& record = iter->value[i];
- RegisterSet usedRegisters = usedRegistersFor(record);
- GPRReg result = record.locations[0].directGPR();
- GPRReg obj = record.locations[1].directGPR();
- StructureStubInfo* stubInfo = codeBlock->addStubInfo();
- stubInfo->codeOrigin = checkIn.codeOrigin();
- stubInfo->patch.baseGPR = static_cast<int8_t>(obj);
- stubInfo->patch.valueGPR = static_cast<int8_t>(result);
- stubInfo->patch.usedRegisters = usedRegisters;
- stubInfo->patch.spillMode = NeedToSpill;
-
- MacroAssembler::Label begin = slowPathJIT.label();
-
- MacroAssembler::Call slowCall = callOperation(
- state, usedRegisters, slowPathJIT, checkIn.codeOrigin(), &exceptionTarget,
- operationInOptimize, result, stubInfo, obj, checkIn.m_uid);
-
- checkIn.m_slowPathDone.append(slowPathJIT.jump());
-
- checkIn.m_generators.append(CheckInGenerator(stubInfo, slowCall, begin));
- }
+ JITPutByIdGenerator gen(
+ codeBlock, putById.codeOrigin(), usedRegisters, callFrameRegister,
+ JSValueRegs(base), JSValueRegs(value), MacroAssembler::scratchRegister,
+ false, putById.ecmaMode(), putById.putKind());
+
+ MacroAssembler::Label begin = slowPathJIT.label();
+
+ MacroAssembler::Call call = callOperation(
+ state, usedRegisters, slowPathJIT, gen.slowPathFunction(), callFrameRegister,
+ gen.stubInfo(), value, base, putById.uid());
+
+ gen.reportSlowPathCall(begin, call);
+
+ putById.m_slowPathDone = slowPathJIT.jump();
+ putById.m_generator = gen;
}
- exceptionTarget.link(&slowPathJIT);
- MacroAssembler::Jump exceptionJump = slowPathJIT.jump();
-
- state.finalizer->sideCodeLinkBuffer = std::make_unique<LinkBuffer>(vm, slowPathJIT, codeBlock, JITCompilationCanFail);
- if (state.finalizer->sideCodeLinkBuffer->didFailToAllocate()) {
- state.allocationFailed = true;
- return;
- }
- state.finalizer->sideCodeLinkBuffer->link(
- exceptionJump, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
+ state.finalizer->sideCodeLinkBuffer = adoptPtr(
+ new LinkBuffer(vm, &slowPathJIT, codeBlock, JITCompilationMustSucceed));
for (unsigned i = state.getByIds.size(); i--;) {
generateICFastPath(
@@ -576,227 +272,108 @@ static void fixFunctionBasedOnStackMaps(
state, codeBlock, generatedFunction, recordMap, state.putByIds[i],
sizeOfPutById());
}
-
- for (unsigned i = state.checkIns.size(); i--;) {
- generateCheckInICFastPath(
- state, codeBlock, generatedFunction, recordMap, state.checkIns[i],
- sizeOfIn());
- }
- }
-
- adjustCallICsForStackmaps(state.jsCalls, recordMap);
-
- for (unsigned i = state.jsCalls.size(); i--;) {
- JSCall& call = state.jsCalls[i];
-
- CCallHelpers fastPathJIT(&vm, codeBlock);
- call.emit(fastPathJIT);
-
- char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
-
- generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfCall(), "JSCall inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
- call.link(vm, linkBuffer);
- });
- }
-
- adjustCallICsForStackmaps(state.jsCallVarargses, recordMap);
-
- for (unsigned i = state.jsCallVarargses.size(); i--;) {
- JSCallVarargs& call = state.jsCallVarargses[i];
-
- CCallHelpers fastPathJIT(&vm, codeBlock);
- call.emit(fastPathJIT, varargsSpillSlotsOffset);
-
- char* startOfIC = bitwise_cast<char*>(generatedFunction) + call.m_instructionOffset;
- size_t sizeOfIC = sizeOfICFor(call.node());
-
- generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, "varargs call inline cache", [&] (LinkBuffer& linkBuffer, CCallHelpers&, bool) {
- call.link(vm, linkBuffer, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
- });
}
RepatchBuffer repatchBuffer(codeBlock);
-
- auto iter = recordMap.find(state.handleStackOverflowExceptionStackmapID);
- // It's sort of remotely possible that we won't have an in-band exception handling
- // path, for some kinds of functions.
- if (iter != recordMap.end()) {
- for (unsigned i = iter->value.size(); i--;) {
- StackMaps::Record& record = iter->value[i];
-
- CodeLocationLabel source = CodeLocationLabel(
- bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
-
- RELEASE_ASSERT(stackOverflowException.isSet());
-
- repatchBuffer.replaceWithJump(source, state.finalizer->handleExceptionsLinkBuffer->locationOf(stackOverflowException));
- }
- }
-
- iter = recordMap.find(state.handleExceptionStackmapID);
- // It's sort of remotely possible that we won't have an in-band exception handling
- // path, for some kinds of functions.
- if (iter != recordMap.end()) {
- for (unsigned i = iter->value.size(); i--;) {
- StackMaps::Record& record = iter->value[i];
-
- CodeLocationLabel source = CodeLocationLabel(
- bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
-
- repatchBuffer.replaceWithJump(source, state.finalizer->handleExceptionsLinkBuffer->entrypoint());
- }
- }
- for (unsigned exitIndex = 0; exitIndex < jitCode->osrExit.size(); ++exitIndex) {
+ for (unsigned exitIndex = jitCode->osrExit.size(); exitIndex--;) {
OSRExitCompilationInfo& info = state.finalizer->osrExit[exitIndex];
OSRExit& exit = jitCode->osrExit[exitIndex];
- iter = recordMap.find(exit.m_stackmapID);
+ StackMaps::RecordMap::iterator iter = recordMap.find(exit.m_stackmapID);
+ if (iter == recordMap.end()) {
+ // This could happen if LLVM optimizes out an OSR exit.
+ continue;
+ }
- Vector<const void*> codeAddresses;
+ StackMaps::Record& record = iter->value;
- if (iter != recordMap.end()) {
- for (unsigned i = iter->value.size(); i--;) {
- StackMaps::Record& record = iter->value[i];
-
- CodeLocationLabel source = CodeLocationLabel(
- bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
-
- codeAddresses.append(bitwise_cast<char*>(generatedFunction) + record.instructionOffset + MacroAssembler::maxJumpReplacementSize());
-
- if (info.m_isInvalidationPoint)
- jitCode->common.jumpReplacements.append(JumpReplacement(source, info.m_thunkAddress));
- else
- repatchBuffer.replaceWithJump(source, info.m_thunkAddress);
- }
+ CodeLocationLabel source = CodeLocationLabel(
+ bitwise_cast<char*>(generatedFunction) + record.instructionOffset);
+
+ if (info.m_isInvalidationPoint) {
+ jitCode->common.jumpReplacements.append(JumpReplacement(source, info.m_thunkAddress));
+ continue;
}
- if (graph.compilation())
- graph.compilation()->addOSRExitSite(codeAddresses);
+ repatchBuffer.replaceWithJump(source, info.m_thunkAddress);
}
}
-void compile(State& state, Safepoint::Result& safepointResult)
+void compile(State& state)
{
char* error = 0;
- {
- GraphSafepoint safepoint(state.graph, safepointResult);
-
- LLVMMCJITCompilerOptions options;
- llvm->InitializeMCJITCompilerOptions(&options, sizeof(options));
- options.OptLevel = Options::llvmBackendOptimizationLevel();
- options.NoFramePointerElim = true;
- if (Options::useLLVMSmallCodeModel())
- options.CodeModel = LLVMCodeModelSmall;
- options.EnableFastISel = enableLLVMFastISel;
- options.MCJMM = llvm->CreateSimpleMCJITMemoryManager(
- &state, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy);
+ LLVMMCJITCompilerOptions options;
+ llvm->InitializeMCJITCompilerOptions(&options, sizeof(options));
+ options.OptLevel = Options::llvmBackendOptimizationLevel();
+ options.NoFramePointerElim = true;
+ if (Options::useLLVMSmallCodeModel())
+ options.CodeModel = LLVMCodeModelSmall;
+ options.EnableFastISel = Options::enableLLVMFastISel();
+ options.MCJMM = llvm->CreateSimpleMCJITMemoryManager(
+ &state, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy);
- LLVMExecutionEngineRef engine;
-
- if (isARM64()) {
-#if OS(DARWIN)
- llvm->SetTarget(state.module, "arm64-apple-ios");
-#elif OS(LINUX)
- llvm->SetTarget(state.module, "aarch64-linux-gnu");
-#else
-#error "Unrecognized OS"
-#endif
- }
-
- if (llvm->CreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) {
- dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
- CRASH();
- }
-
- // At this point we no longer own the module.
- LModule module = state.module;
- state.module = nullptr;
-
- // The data layout also has to be set in the module. Get the data layout from the MCJIT and apply
- // it to the module.
- LLVMTargetMachineRef targetMachine = llvm->GetExecutionEngineTargetMachine(engine);
- LLVMTargetDataRef targetData = llvm->GetExecutionEngineTargetData(engine);
- char* stringRepOfTargetData = llvm->CopyStringRepOfTargetData(targetData);
- llvm->SetDataLayout(module, stringRepOfTargetData);
- free(stringRepOfTargetData);
-
- LLVMPassManagerRef functionPasses = 0;
- LLVMPassManagerRef modulePasses;
-
- if (Options::llvmSimpleOpt()) {
- modulePasses = llvm->CreatePassManager();
- llvm->AddTargetData(targetData, modulePasses);
- llvm->AddAnalysisPasses(targetMachine, modulePasses);
- llvm->AddPromoteMemoryToRegisterPass(modulePasses);
- llvm->AddGlobalOptimizerPass(modulePasses);
- llvm->AddFunctionInliningPass(modulePasses);
- llvm->AddPruneEHPass(modulePasses);
- llvm->AddGlobalDCEPass(modulePasses);
- llvm->AddConstantPropagationPass(modulePasses);
- llvm->AddAggressiveDCEPass(modulePasses);
- llvm->AddInstructionCombiningPass(modulePasses);
- // BEGIN - DO NOT CHANGE THE ORDER OF THE ALIAS ANALYSIS PASSES
- llvm->AddTypeBasedAliasAnalysisPass(modulePasses);
- llvm->AddBasicAliasAnalysisPass(modulePasses);
- // END - DO NOT CHANGE THE ORDER OF THE ALIAS ANALYSIS PASSES
- llvm->AddGVNPass(modulePasses);
- llvm->AddCFGSimplificationPass(modulePasses);
- llvm->AddDeadStoreEliminationPass(modulePasses);
-
- if (enableLLVMFastISel)
- llvm->AddLowerSwitchPass(modulePasses);
-
- llvm->RunPassManager(modulePasses, module);
- } else {
- LLVMPassManagerBuilderRef passBuilder = llvm->PassManagerBuilderCreate();
- llvm->PassManagerBuilderSetOptLevel(passBuilder, Options::llvmOptimizationLevel());
- llvm->PassManagerBuilderUseInlinerWithThreshold(passBuilder, 275);
- llvm->PassManagerBuilderSetSizeLevel(passBuilder, Options::llvmSizeLevel());
-
- functionPasses = llvm->CreateFunctionPassManagerForModule(module);
- modulePasses = llvm->CreatePassManager();
-
- llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
-
- llvm->PassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses);
- llvm->PassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
-
- llvm->PassManagerBuilderDispose(passBuilder);
-
- llvm->InitializeFunctionPassManager(functionPasses);
- for (LValue function = llvm->GetFirstFunction(module); function; function = llvm->GetNextFunction(function))
- llvm->RunFunctionPassManager(functionPasses, function);
- llvm->FinalizeFunctionPassManager(functionPasses);
-
- llvm->RunPassManager(modulePasses, module);
- }
-
- if (shouldShowDisassembly() || verboseCompilationEnabled())
- state.dumpState(module, "after optimization");
-
- // FIXME: Need to add support for the case where JIT memory allocation failed.
- // https://bugs.webkit.org/show_bug.cgi?id=113620
- state.generatedFunction = reinterpret_cast<GeneratedFunction>(llvm->GetPointerToGlobal(engine, state.function));
- if (functionPasses)
- llvm->DisposePassManager(functionPasses);
- llvm->DisposePassManager(modulePasses);
- llvm->DisposeExecutionEngine(engine);
+ LLVMExecutionEngineRef engine;
+
+ if (llvm->CreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) {
+ dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
+ CRASH();
}
- if (safepointResult.didGetCancelled())
- return;
- RELEASE_ASSERT(!state.graph.m_vm.heap.isCollecting());
+ LLVMPassManagerRef functionPasses = 0;
+ LLVMPassManagerRef modulePasses;
- if (state.allocationFailed)
- return;
+ if (Options::llvmSimpleOpt()) {
+ modulePasses = llvm->CreatePassManager();
+ llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
+ llvm->AddPromoteMemoryToRegisterPass(modulePasses);
+ llvm->AddConstantPropagationPass(modulePasses);
+ llvm->AddInstructionCombiningPass(modulePasses);
+ llvm->AddBasicAliasAnalysisPass(modulePasses);
+ llvm->AddTypeBasedAliasAnalysisPass(modulePasses);
+ llvm->AddGVNPass(modulePasses);
+ llvm->AddCFGSimplificationPass(modulePasses);
+ llvm->RunPassManager(modulePasses, state.module);
+ } else {
+ LLVMPassManagerBuilderRef passBuilder = llvm->PassManagerBuilderCreate();
+ llvm->PassManagerBuilderSetOptLevel(passBuilder, Options::llvmOptimizationLevel());
+ llvm->PassManagerBuilderSetSizeLevel(passBuilder, Options::llvmSizeLevel());
+
+ functionPasses = llvm->CreateFunctionPassManagerForModule(state.module);
+ modulePasses = llvm->CreatePassManager();
+
+ llvm->AddTargetData(llvm->GetExecutionEngineTargetData(engine), modulePasses);
+
+ llvm->PassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses);
+ llvm->PassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
+
+ llvm->PassManagerBuilderDispose(passBuilder);
+
+ llvm->InitializeFunctionPassManager(functionPasses);
+ for (LValue function = llvm->GetFirstFunction(state.module); function; function = llvm->GetNextFunction(function))
+ llvm->RunFunctionPassManager(functionPasses, function);
+ llvm->FinalizeFunctionPassManager(functionPasses);
+
+ llvm->RunPassManager(modulePasses, state.module);
+ }
+
+ if (DFG::shouldShowDisassembly() || DFG::verboseCompilationEnabled())
+ state.dumpState("after optimization");
+ // FIXME: Need to add support for the case where JIT memory allocation failed.
+ // https://bugs.webkit.org/show_bug.cgi?id=113620
+ state.generatedFunction = reinterpret_cast<GeneratedFunction>(llvm->GetPointerToGlobal(engine, state.function));
+ if (functionPasses)
+ llvm->DisposePassManager(functionPasses);
+ llvm->DisposePassManager(modulePasses);
+ llvm->DisposeExecutionEngine(engine);
+
if (shouldShowDisassembly()) {
for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
dataLog(
"Generated LLVM code for ",
- CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
+ CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::DFGJIT),
" #", i, ", ", state.codeSectionNames[i], ":\n");
disassemble(
MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(),
@@ -804,37 +381,26 @@ void compile(State& state, Safepoint::Result& safepointResult)
}
for (unsigned i = 0; i < state.jitCode->dataSections().size(); ++i) {
- DataSection* section = state.jitCode->dataSections()[i].get();
+ const RefCountedArray<LSectionWord>& section = state.jitCode->dataSections()[i];
dataLog(
"Generated LLVM data section for ",
- CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
+ CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::DFGJIT),
" #", i, ", ", state.dataSectionNames[i], ":\n");
dumpDataSection(section, " ");
}
}
- bool didSeeUnwindInfo = state.jitCode->unwindInfo.parse(
- state.unwindDataSection, state.unwindDataSectionSize,
- state.generatedFunction);
- if (shouldShowDisassembly()) {
- dataLog("Unwind info for ", CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n");
- if (didSeeUnwindInfo)
- dataLog(" ", state.jitCode->unwindInfo, "\n");
- else
- dataLog(" <no unwind info>\n");
- }
-
- if (state.stackmapsSection && state.stackmapsSection->size()) {
+ if (state.stackmapsSection.size()) {
if (shouldShowDisassembly()) {
dataLog(
"Generated LLVM stackmaps section for ",
- CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT), ":\n");
+ CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::DFGJIT), ":\n");
dataLog(" Raw data:\n");
- dumpDataSection(state.stackmapsSection.get(), " ");
+ dumpDataSection(state.stackmapsSection, " ");
}
RefPtr<DataView> stackmapsData = DataView::create(
- ArrayBuffer::create(state.stackmapsSection->base(), state.stackmapsSection->size()));
+ ArrayBuffer::create(state.stackmapsSection.data(), state.stackmapsSection.byteSize()));
state.jitCode->stackmaps.parse(stackmapsData.get());
if (shouldShowDisassembly()) {
@@ -842,40 +408,29 @@ void compile(State& state, Safepoint::Result& safepointResult)
state.jitCode->stackmaps.dumpMultiline(WTF::dataFile(), " ");
}
- StackMaps::RecordMap recordMap = state.jitCode->stackmaps.computeRecordMap();
+ StackMaps::RecordMap recordMap = state.jitCode->stackmaps.getRecordMap();
fixFunctionBasedOnStackMaps(
state, state.graph.m_codeBlock, state.jitCode.get(), state.generatedFunction,
- recordMap, didSeeUnwindInfo);
- if (state.allocationFailed)
- return;
+ recordMap);
- if (shouldShowDisassembly() || Options::asyncDisassembly()) {
+ if (shouldShowDisassembly()) {
for (unsigned i = 0; i < state.jitCode->handles().size(); ++i) {
- if (state.codeSectionNames[i] != SECTION_NAME("text"))
+ if (state.codeSectionNames[i] != "__text")
continue;
ExecutableMemoryHandle* handle = state.jitCode->handles()[i].get();
-
- CString header = toCString(
+ dataLog(
"Generated LLVM code after stackmap-based fix-up for ",
- CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::FTLJIT),
- " in ", state.graph.m_plan.mode, " #", i, ", ",
- state.codeSectionNames[i], ":\n");
-
- if (Options::asyncDisassembly()) {
- disassembleAsynchronously(
- header, MacroAssemblerCodeRef(handle), handle->sizeInBytes(), " ",
- LLVMSubset);
- continue;
- }
-
- dataLog(header);
+ CodeBlockWithJITType(state.graph.m_codeBlock, JITCode::DFGJIT),
+ " #", i, ", ", state.codeSectionNames[i], ":\n");
disassemble(
MacroAssemblerCodePtr(handle->start()), handle->sizeInBytes(),
" ", WTF::dataFile(), LLVMSubset);
}
}
}
+
+ state.module = 0; // We no longer own the module.
}
} } // namespace JSC::FTL