Create an FTLExceptionHandlerManager abstraction
https://bugs.webkit.org/show_bug.cgi?id=151079
Reviewed by Mark Lam.
Before, we used to manage the {stackmapRecordIndex => OSRExit} relationship
for exception handlers with a locally allocated HashMap and a few different
lambdas and random checks. It's cleaner and more manageable to just create
a class that handles this abstraction for us. This class provides nice helper
functions for everything we need. This abstraction makes reading the code easier.
And it will also makes hacking on the code in the future easier.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGOSRExitBase.h:
(JSC::DFG::OSRExitBase::OSRExitBase):
* ftl/FTLCompile.cpp:
(JSC::FTL::mmAllocateDataSection):
* ftl/FTLExceptionHandlerManager.cpp: Added.
(JSC::FTL::ExceptionHandlerManager::ExceptionHandlerManager):
(JSC::FTL::ExceptionHandlerManager::addNewExit):
(JSC::FTL::ExceptionHandlerManager::getOrPutByIdCallOperationExceptionTarget):
(JSC::FTL::ExceptionHandlerManager::lazySlowPathExceptionTarget):
(JSC::FTL::ExceptionHandlerManager::getByIdOSRExit):
(JSC::FTL::ExceptionHandlerManager::getCallOSRExitCommon):
(JSC::FTL::ExceptionHandlerManager::getCallOSRExit):
(JSC::FTL::ExceptionHandlerManager::procureCallSiteIndex):
* ftl/FTLExceptionHandlerManager.h: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@192273 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index c761d93..6fa34c0 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -985,6 +985,7 @@
ftl/FTLDWARFDebugLineInfo.cpp
ftl/FTLDWARFRegister.cpp
ftl/FTLDataSection.cpp
+ ftl/FTLExceptionHandlerManager.cpp
ftl/FTLExitArgument.cpp
ftl/FTLExitArgumentForOperand.cpp
ftl/FTLExitPropertyValue.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index beec10e..ed8a20e 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,36 @@
+2015-11-10 Saam barati <sbarati@apple.com>
+
+ Create an FTLExceptionHandlerManager abstraction
+ https://bugs.webkit.org/show_bug.cgi?id=151079
+
+ Reviewed by Mark Lam.
+
+ Before, we used to manage the {stackmapRecordIndex => OSRExit} relationship
+ for exception handlers with a locally allocated HashMap and a few different
+ lambdas and random checks. It's cleaner and more manageable to just create
+ a class that handles this abstraction for us. This class provides nice helper
+ functions for everything we need. This abstraction makes reading the code easier.
+ And it will also makes hacking on the code in the future easier.
+
+ * CMakeLists.txt:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * dfg/DFGOSRExitBase.h:
+ (JSC::DFG::OSRExitBase::OSRExitBase):
+ * ftl/FTLCompile.cpp:
+ (JSC::FTL::mmAllocateDataSection):
+ * ftl/FTLExceptionHandlerManager.cpp: Added.
+ (JSC::FTL::ExceptionHandlerManager::ExceptionHandlerManager):
+ (JSC::FTL::ExceptionHandlerManager::addNewExit):
+ (JSC::FTL::ExceptionHandlerManager::getOrPutByIdCallOperationExceptionTarget):
+ (JSC::FTL::ExceptionHandlerManager::lazySlowPathExceptionTarget):
+ (JSC::FTL::ExceptionHandlerManager::getByIdOSRExit):
+ (JSC::FTL::ExceptionHandlerManager::getCallOSRExitCommon):
+ (JSC::FTL::ExceptionHandlerManager::getCallOSRExit):
+ (JSC::FTL::ExceptionHandlerManager::procureCallSiteIndex):
+ * ftl/FTLExceptionHandlerManager.h: Added.
+
2015-11-10 Michael Saboff <msaboff@apple.com>
X86_64 support for compareDouble(DoubleCondition, FPRegisterID left, FPRegisterID right, RegisterID dest)
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
index 29b94ca..284f587 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
@@ -525,6 +525,7 @@
<ClCompile Include="..\ftl\FTLDataSection.cpp" />
<ClCompile Include="..\ftl\FTLDWARFDebugLineInfo.cpp" />
<ClCompile Include="..\ftl\FTLDWARFRegister.cpp" />
+ <ClCompile Include="..\ftl\FTLExceptionHandlerManager.cpp" />
<ClCompile Include="..\ftl\FTLExitArgument.cpp" />
<ClCompile Include="..\ftl\FTLExitArgumentForOperand.cpp" />
<ClCompile Include="..\ftl\FTLExitPropertyValue.cpp" />
@@ -1290,6 +1291,7 @@
<ClInclude Include="..\ftl\FTLDataSection.h" />
<ClInclude Include="..\ftl\FTLDWARFDebugLineInfo.h" />
<ClInclude Include="..\ftl\FTLDWARFRegister.h" />
+ <ClInclude Include="..\ftl\FTLExceptionHandlerManager.h" />
<ClInclude Include="..\ftl\FTLExitArgument.h" />
<ClInclude Include="..\ftl\FTLExitArgumentForOperand.h" />
<ClInclude Include="..\ftl\FTLStackmapArgumentList.h" />
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
index e29f8fb..91781a2 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
+++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
@@ -1563,6 +1563,9 @@
<ClCompile Include="..\ftl\FTLDWARFRegister.cpp">
<Filter>ftl</Filter>
</ClCompile>
+ <ClCompile Include="..\ftl\FTLExceptionHandlerManager.cpp">
+ <Filter>ftl</Filter>
+ </ClCompile>
<ClCompile Include="..\ftl\FTLExitArgument.cpp">
<Filter>ftl</Filter>
</ClCompile>
@@ -4120,6 +4123,9 @@
<ClInclude Include="..\ftl\FTLDWARFRegister.h">
<Filter>ftl</Filter>
</ClInclude>
+ <ClInclude Include="..\ftl\FTLExceptionHandlerManager.h">
+ <Filter>ftl</Filter>
+ </ClInclude>
<ClInclude Include="..\ftl\FTLExitArgument.h">
<Filter>ftl</Filter>
</ClInclude>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index bd28b3e..5af4bd8 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -1206,6 +1206,8 @@
797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
79C4B15D1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */; };
79C4B15E1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 79C4B15C1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 79DF66B01BF26A570001CF11 /* FTLExceptionHandlerManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79DF66AE1BF26A570001CF11 /* FTLExceptionHandlerManager.cpp */; };
+ 79DF66B11BF26A570001CF11 /* FTLExceptionHandlerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 79DF66AF1BF26A570001CF11 /* FTLExceptionHandlerManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */; };
79EE0C001B4AFB85000385C9 /* VariableEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
79F8FC1E1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */; };
@@ -3252,6 +3254,8 @@
797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; };
79C4B15B1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLiveCatchVariablePreservationPhase.cpp; path = dfg/DFGLiveCatchVariablePreservationPhase.cpp; sourceTree = "<group>"; };
79C4B15C1BA2158F00FD592E /* DFGLiveCatchVariablePreservationPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLiveCatchVariablePreservationPhase.h; path = dfg/DFGLiveCatchVariablePreservationPhase.h; sourceTree = "<group>"; };
+ 79DF66AE1BF26A570001CF11 /* FTLExceptionHandlerManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLExceptionHandlerManager.cpp; path = ftl/FTLExceptionHandlerManager.cpp; sourceTree = "<group>"; };
+ 79DF66AF1BF26A570001CF11 /* FTLExceptionHandlerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLExceptionHandlerManager.h; path = ftl/FTLExceptionHandlerManager.h; sourceTree = "<group>"; };
79EE0BFD1B4AFB85000385C9 /* VariableEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableEnvironment.cpp; sourceTree = "<group>"; };
79EE0BFE1B4AFB85000385C9 /* VariableEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableEnvironment.h; sourceTree = "<group>"; };
79F8FC1C1B9FED0F00CA66AB /* DFGMaximalFlushInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMaximalFlushInsertionPhase.cpp; path = dfg/DFGMaximalFlushInsertionPhase.cpp; sourceTree = "<group>"; };
@@ -4338,6 +4342,8 @@
2AC922BA18A16182003CE0FB /* FTLDWARFDebugLineInfo.h */,
0F9C5E5C18E35F5E00D431C3 /* FTLDWARFRegister.cpp */,
0F9C5E5D18E35F5E00D431C3 /* FTLDWARFRegister.h */,
+ 79DF66AE1BF26A570001CF11 /* FTLExceptionHandlerManager.cpp */,
+ 79DF66AF1BF26A570001CF11 /* FTLExceptionHandlerManager.h */,
0F235BBD17178E1C00690C7F /* FTLExitArgument.cpp */,
0F235BBE17178E1C00690C7F /* FTLExitArgument.h */,
0F235BBF17178E1C00690C7F /* FTLExitArgumentForOperand.cpp */,
@@ -6582,6 +6588,7 @@
0F4570391BE44C910062A629 /* AirEliminateDeadCode.h in Headers */,
0FEC85771BDACDC70080FF74 /* AirFrequentedBlock.h in Headers */,
0FEC85791BDACDC70080FF74 /* AirGenerate.h in Headers */,
+ 79DF66B11BF26A570001CF11 /* FTLExceptionHandlerManager.h in Headers */,
0FEC857A1BDACDC70080FF74 /* AirGenerationContext.h in Headers */,
0FEC857C1BDACDC70080FF74 /* AirHandleCalleeSaves.h in Headers */,
0FEC857E1BDACDC70080FF74 /* AirInsertionSet.h in Headers */,
@@ -8700,6 +8707,7 @@
0F2B66FE17B6B5AB00A7AE3F /* JSTypedArrays.cpp in Sources */,
534C457E1BC72549007476A7 /* JSTypedArrayViewConstructor.cpp in Sources */,
DEA7E2441BBC677200D78440 /* JSTypedArrayViewPrototype.cpp in Sources */,
+ 79DF66B01BF26A570001CF11 /* FTLExceptionHandlerManager.cpp in Sources */,
86E3C61A167BABEE006D760A /* JSValue.mm in Sources */,
14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */,
86E3C61C167BABEE006D760A /* JSVirtualMachine.mm in Sources */,
diff --git a/Source/JavaScriptCore/dfg/DFGOSRExitBase.h b/Source/JavaScriptCore/dfg/DFGOSRExitBase.h
index e4af1c7..eafd9c7 100644
--- a/Source/JavaScriptCore/dfg/DFGOSRExitBase.h
+++ b/Source/JavaScriptCore/dfg/DFGOSRExitBase.h
@@ -45,7 +45,6 @@
, m_count(0)
, m_codeOrigin(origin)
, m_codeOriginForExitProfile(originForProfile)
- , m_exceptionHandlerCallSiteIndex(std::numeric_limits<unsigned>::max())
, m_isExceptionHandler(false)
{
ASSERT(m_codeOrigin.isSet());
diff --git a/Source/JavaScriptCore/ftl/FTLCompile.cpp b/Source/JavaScriptCore/ftl/FTLCompile.cpp
index 8ccc999..6b063f8 100644
--- a/Source/JavaScriptCore/ftl/FTLCompile.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCompile.cpp
@@ -37,6 +37,7 @@
#include "DFGOperations.h"
#include "DataView.h"
#include "Disassembler.h"
+#include "FTLExceptionHandlerManager.h"
#include "FTLExitThunkGenerator.h"
#include "FTLInlineCacheSize.h"
#include "FTLJITCode.h"
@@ -466,7 +467,7 @@
}
template<typename CallType>
-void adjustCallICsForStackmaps(Vector<CallType>& calls, StackMaps::RecordMap& recordMap, std::function<CallSiteIndex (uint32_t recordIndex, CodeOrigin origin)> generateCallSiteIndexFunction, std::function<OSRExit* (uint32_t recordIndex)> getCorrespondingOSRExit)
+void adjustCallICsForStackmaps(Vector<CallType>& calls, StackMaps::RecordMap& recordMap, ExceptionHandlerManager& exceptionHandlerManager)
{
// 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.
@@ -484,8 +485,8 @@
for (unsigned j = 0; j < iter->value.size(); ++j) {
CallType copy = call;
copy.m_instructionOffset = iter->value[j].record.instructionOffset;
- copy.setCallSiteIndex(generateCallSiteIndexFunction(iter->value[j].index, copy.callSiteDescriptionOrigin()));
- copy.setCorrespondingGenericUnwindOSRExit(getCorrespondingOSRExit(iter->value[j].index));
+ copy.setCallSiteIndex(exceptionHandlerManager.procureCallSiteIndex(iter->value[j].index, copy));
+ copy.setCorrespondingGenericUnwindOSRExit(exceptionHandlerManager.getCallOSRExit(iter->value[j].index, copy));
calls.append(copy);
}
@@ -502,29 +503,7 @@
VM& vm = graph.m_vm;
StackMaps& stackmaps = jitCode->stackmaps;
- // We fill this when generating OSR exits that will be executed via genericUnwind()
- // or lazy slow path exception checks.
- // That way, when we assign a CallSiteIndex to the Call/GetById/PutById/LazySlowPath, we assign
- // it the proper CallSiteIndex that corresponds to the OSRExit exception handler.
- HashMap<uint32_t, size_t, WTF::IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> recordIndexToGenericUnwindOrLazySlowPathOSRExit;
- auto generateOrGetAlreadyGeneratedCallSiteIndex = [&] (uint32_t recordIndex, CodeOrigin origin) -> CallSiteIndex {
- auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
- if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
- return state.jitCode->common.addUniqueCallSiteIndex(origin);
- size_t osrExitIndex = findResult->value;
- return state.jitCode->osrExit[osrExitIndex].m_exceptionHandlerCallSiteIndex;
- };
- auto jsCallOSRExitForRecordIndex = [&] (uint32_t recordIndex) -> OSRExit* {
- auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
- if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
- return nullptr;
-
- size_t osrExitIndex = findResult->value;
- OSRExit& exit = state.jitCode->osrExit[osrExitIndex];
- if (!exit.m_descriptor.m_isExceptionFromJSCall)
- return nullptr;
- return &exit;
- };
+ ExceptionHandlerManager exceptionHandlerManager(state);
int localsOffset = offsetOfStackRegion(recordMap, state.capturedStackmapID) + graph.m_nextMachineLocal;
int varargsSpillSlotsOffset = offsetOfStackRegion(recordMap, state.varargsSpillSlotsStackmapID);
@@ -610,7 +589,7 @@
RELEASE_ASSERT(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader.isSet());
CallSiteIndex callSiteIndex = state.jitCode->common.addUniqueCallSiteIndex(exit.m_descriptor.m_semanticCodeOriginForCallFrameHeader);
exit.m_exceptionHandlerCallSiteIndex = callSiteIndex;
- recordIndexToGenericUnwindOrLazySlowPathOSRExit.add(iter->value[j].index, state.jitCode->osrExit.size() - 1);
+ exceptionHandlerManager.addNewExit(iter->value[j].index, state.jitCode->osrExit.size() - 1);
if (exitDescriptor.m_isExceptionFromJSCall)
exit.gatherRegistersToSpillForCallIfException(stackmaps, record);
@@ -683,16 +662,11 @@
Vector<std::pair<CCallHelpers::JumpList, CodeLocationLabel>> exceptionJumpsToLink;
auto addNewExceptionJumpIfNecessary = [&] (uint32_t recordIndex) {
- auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(recordIndex);
- if (findResult == recordIndexToGenericUnwindOrLazySlowPathOSRExit.end())
+ CodeLocationLabel exceptionTarget = exceptionHandlerManager.getOrPutByIdCallOperationExceptionTarget(recordIndex);
+ if (!exceptionTarget)
return false;
-
- size_t osrExitIndex = findResult->value;
- RELEASE_ASSERT(state.jitCode->osrExit[osrExitIndex].m_descriptor.m_willArriveAtOSRExitFromGenericUnwind);
- OSRExitCompilationInfo& info = state.finalizer->osrExit[osrExitIndex];
- RELEASE_ASSERT(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance.isSet());
exceptionJumpsToLink.append(
- std::make_pair(CCallHelpers::JumpList(), state.finalizer->exitThunksLinkBuffer->locationOf(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance)));
+ std::make_pair(CCallHelpers::JumpList(), exceptionTarget));
return true;
};
@@ -718,7 +692,7 @@
GPRReg base = record.locations[1].directGPR();
JITGetByIdGenerator gen(
- codeBlock, codeOrigin, generateOrGetAlreadyGeneratedCallSiteIndex(iter->value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
+ codeBlock, codeOrigin, exceptionHandlerManager.procureCallSiteIndex(iter->value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
JSValueRegs(result));
bool addedUniqueExceptionJump = addNewExceptionJumpIfNecessary(iter->value[i].index);
@@ -733,13 +707,8 @@
// register that we would like to do value recovery on. We combat this situation from ever
// taking place by ensuring we spill the original base value and then recover it from
// the spill slot as the first step in OSR exit.
- auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(iter->value[i].index);
- if (findResult != recordIndexToGenericUnwindOrLazySlowPathOSRExit.end()) {
- size_t osrExitIndex = findResult->value;
- OSRExit& exit = state.jitCode->osrExit[osrExitIndex];
- RELEASE_ASSERT(exit.m_descriptor.m_isExceptionFromGetById);
- exit.spillRegistersToSpillSlot(slowPathJIT, jsCallThatMightThrowSpillOffset);
- }
+ if (OSRExit* exit = exceptionHandlerManager.getByIdOSRExit(iter->value[i].index))
+ exit->spillRegistersToSpillSlot(slowPathJIT, jsCallThatMightThrowSpillOffset);
}
MacroAssembler::Call call = callOperation(
state, usedRegisters, slowPathJIT, codeOrigin, addedUniqueExceptionJump ? &exceptionJumpsToLink.last().first : &exceptionTarget,
@@ -775,7 +744,7 @@
GPRReg value = record.locations[1].directGPR();
JITPutByIdGenerator gen(
- codeBlock, codeOrigin, generateOrGetAlreadyGeneratedCallSiteIndex(iter->value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
+ codeBlock, codeOrigin, exceptionHandlerManager.procureCallSiteIndex(iter->value[i].index, codeOrigin), usedRegisters, JSValueRegs(base),
JSValueRegs(value), GPRInfo::patchpointScratchRegister, putById.ecmaMode(), putById.putKind());
bool addedUniqueExceptionJump = addNewExceptionJumpIfNecessary(iter->value[i].index);
@@ -883,18 +852,12 @@
char* startOfIC =
bitwise_cast<char*>(generatedFunction) + record.instructionOffset;
CodeLocationLabel patchpoint((MacroAssemblerCodePtr(startOfIC)));
- CodeLocationLabel exceptionTarget;
- auto findResult = recordIndexToGenericUnwindOrLazySlowPathOSRExit.find(iter->value[i].index);
- if (findResult != recordIndexToGenericUnwindOrLazySlowPathOSRExit.end()) {
- size_t osrExitIndex = findResult->value;
- OSRExitCompilationInfo& info = state.finalizer->osrExit[osrExitIndex];
- RELEASE_ASSERT(state.jitCode->osrExit[osrExitIndex].m_descriptor.m_isExceptionFromLazySlowPath);
- exceptionTarget = state.finalizer->exitThunksLinkBuffer->locationOf(info.m_thunkLabel);
- } else
+ CodeLocationLabel exceptionTarget = exceptionHandlerManager.lazySlowPathExceptionTarget(iter->value[i].index);
+ if (!exceptionTarget)
exceptionTarget = state.finalizer->handleExceptionsLinkBuffer->entrypoint();
std::unique_ptr<LazySlowPath> lazySlowPath = std::make_unique<LazySlowPath>(
- patchpoint, exceptionTarget, usedRegisters, generateOrGetAlreadyGeneratedCallSiteIndex(iter->value[i].index, codeOrigin),
+ patchpoint, exceptionTarget, usedRegisters, exceptionHandlerManager.procureCallSiteIndex(iter->value[i].index, codeOrigin),
descriptor.m_linker->run(locations));
CCallHelpers::Label begin = slowPathJIT.label();
@@ -952,7 +915,7 @@
state.finalizer->sideCodeLinkBuffer->link(pair.first, pair.second);
}
- adjustCallICsForStackmaps(state.jsCalls, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
+ adjustCallICsForStackmaps(state.jsCalls, recordMap, exceptionHandlerManager);
for (unsigned i = state.jsCalls.size(); i--;) {
JSCall& call = state.jsCalls[i];
@@ -967,7 +930,7 @@
});
}
- adjustCallICsForStackmaps(state.jsCallVarargses, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
+ adjustCallICsForStackmaps(state.jsCallVarargses, recordMap, exceptionHandlerManager);
for (unsigned i = state.jsCallVarargses.size(); i--;) {
JSCallVarargs& call = state.jsCallVarargses[i];
@@ -983,9 +946,7 @@
});
}
- // FIXME: We shouldn't generate CallSite indices for tail calls.
- // https://bugs.webkit.org/show_bug.cgi?id=151079
- adjustCallICsForStackmaps(state.jsTailCalls, recordMap, generateOrGetAlreadyGeneratedCallSiteIndex, jsCallOSRExitForRecordIndex);
+ adjustCallICsForStackmaps(state.jsTailCalls, recordMap, exceptionHandlerManager);
for (unsigned i = state.jsTailCalls.size(); i--;) {
JSTailCall& call = state.jsTailCalls[i];
diff --git a/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp b/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp
new file mode 100644
index 0000000..710db2d
--- /dev/null
+++ b/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FTLExceptionHandlerManager.h"
+
+#if ENABLE(FTL_JIT)
+
+#include "FTLState.h"
+
+namespace JSC { namespace FTL {
+
+ExceptionHandlerManager::ExceptionHandlerManager(State& state)
+ : m_state(state)
+{
+}
+
+void ExceptionHandlerManager::addNewExit(uint32_t stackmapRecordIndex, size_t osrExitIndex)
+{
+ m_map.add(stackmapRecordIndex, osrExitIndex);
+ OSRExit& exit = m_state.jitCode->osrExit[osrExitIndex];
+ RELEASE_ASSERT(exit.m_descriptor.m_willArriveAtOSRExitFromGenericUnwind || exit.m_descriptor.m_isExceptionFromLazySlowPath);
+}
+
+CodeLocationLabel ExceptionHandlerManager::getOrPutByIdCallOperationExceptionTarget(uint32_t stackmapRecordIndex)
+{
+ auto findResult = m_map.find(stackmapRecordIndex);
+ if (findResult == m_map.end())
+ return CodeLocationLabel();
+
+ size_t osrExitIndex = findResult->value;
+ RELEASE_ASSERT(m_state.jitCode->osrExit[osrExitIndex].m_descriptor.m_willArriveAtOSRExitFromGenericUnwind);
+ OSRExitCompilationInfo& info = m_state.finalizer->osrExit[osrExitIndex];
+ RELEASE_ASSERT(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance.isSet());
+ return m_state.finalizer->exitThunksLinkBuffer->locationOf(info.m_getAndPutByIdCallOperationExceptionOSRExitEntrance);
+}
+
+CodeLocationLabel ExceptionHandlerManager::lazySlowPathExceptionTarget(uint32_t stackmapRecordIndex)
+{
+ auto findResult = m_map.find(stackmapRecordIndex);
+ if (findResult == m_map.end())
+ return CodeLocationLabel();
+
+ size_t osrExitIndex = findResult->value;
+ RELEASE_ASSERT(m_state.jitCode->osrExit[osrExitIndex].m_descriptor.m_isExceptionFromLazySlowPath);
+ OSRExitCompilationInfo& info = m_state.finalizer->osrExit[osrExitIndex];
+ RELEASE_ASSERT(info.m_thunkLabel.isSet());
+ return m_state.finalizer->exitThunksLinkBuffer->locationOf(info.m_thunkLabel);
+}
+
+OSRExit* ExceptionHandlerManager::getByIdOSRExit(uint32_t stackmapRecordIndex)
+{
+ auto findResult = m_map.find(stackmapRecordIndex);
+ if (findResult == m_map.end())
+ return nullptr;
+ size_t osrExitIndex = findResult->value;
+ OSRExit* exit = &m_state.jitCode->osrExit[osrExitIndex];
+ RELEASE_ASSERT(exit->m_descriptor.m_isExceptionFromGetById);
+ return exit;
+}
+
+OSRExit* ExceptionHandlerManager::getCallOSRExitCommon(uint32_t stackmapRecordIndex)
+{
+ auto findResult = m_map.find(stackmapRecordIndex);
+ if (findResult == m_map.end())
+ return nullptr;
+ size_t osrExitIndex = findResult->value;
+ OSRExit* exit = &m_state.jitCode->osrExit[osrExitIndex];
+ RELEASE_ASSERT(exit->m_descriptor.m_isExceptionFromJSCall);
+ return exit;
+}
+
+OSRExit* ExceptionHandlerManager::getCallOSRExit(uint32_t stackmapRecordIndex, const JSCall&)
+{
+ return getCallOSRExitCommon(stackmapRecordIndex);
+}
+
+OSRExit* ExceptionHandlerManager::getCallOSRExit(uint32_t stackmapRecordIndex, const JSCallVarargs&)
+{
+ return getCallOSRExitCommon(stackmapRecordIndex);
+}
+
+OSRExit* ExceptionHandlerManager::getCallOSRExit(uint32_t stackmapRecordIndex, const JSTailCall& call)
+{
+ UNUSED_PARAM(stackmapRecordIndex);
+ UNUSED_PARAM(call);
+ // A call can't be in tail position inside a try block.
+ ASSERT(m_map.find(stackmapRecordIndex) == m_map.end());
+ return nullptr;
+}
+
+CallSiteIndex ExceptionHandlerManager::procureCallSiteIndex(uint32_t stackmapRecordIndex, CodeOrigin origin)
+{
+ auto findResult = m_map.find(stackmapRecordIndex);
+ if (findResult == m_map.end())
+ return m_state.jitCode->common.addUniqueCallSiteIndex(origin);
+ size_t osrExitIndex = findResult->value;
+ OSRExit& exit = m_state.jitCode->osrExit[osrExitIndex];
+ RELEASE_ASSERT(exit.m_exceptionHandlerCallSiteIndex);
+ return exit.m_exceptionHandlerCallSiteIndex;
+}
+
+CallSiteIndex ExceptionHandlerManager::procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSCall& call)
+{
+ return procureCallSiteIndex(stackmapRecordIndex, call.callSiteDescriptionOrigin());
+}
+
+CallSiteIndex ExceptionHandlerManager::procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSCallVarargs& call)
+{
+ return procureCallSiteIndex(stackmapRecordIndex, call.callSiteDescriptionOrigin());
+}
+
+CallSiteIndex ExceptionHandlerManager::procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSTailCall& call)
+{
+ UNUSED_PARAM(stackmapRecordIndex);
+ UNUSED_PARAM(call);
+ // We don't need to generate a call site index for tail calls
+ // because they don't store a CallSiteIndex on the call frame.
+ return CallSiteIndex();
+}
+
+} } // namespace JSC::FTL
+
+#endif // ENABLE(FTL_JIT)
diff --git a/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h b/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h
new file mode 100644
index 0000000..f5309f7
--- /dev/null
+++ b/Source/JavaScriptCore/ftl/FTLExceptionHandlerManager.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTLExceptionHandlerManager_h
+#define FTLExceptionHandlerManager_h
+
+#if ENABLE(FTL_JIT)
+
+#include "CallFrame.h"
+#include "FTLJSCall.h"
+#include "FTLJSCallVarargs.h"
+#include "FTLJSTailCall.h"
+
+namespace JSC { namespace FTL {
+
+// This class is intented to be used during FTLCompile to manage some common tasks
+// needed to query the correspondence between stackmap records and OSR exits that are
+// exception handlers. The only kind of OSR exits we keep are those OSR exits that
+// correspond to exceptions from patchpoints. That means exits from lazy slow paths,
+// JS calls, Get/Put ById, etc. Note: this means we don't keep track of exception checks
+// after C calls because those are modeled explictly in LLVM IR as a branch to a stackmap
+// intrinsic. These patchpoint OSR exits that this class keeps track of are not branched to
+// directly within LLVM IR. We jump to these OSR exits from generated patchpoint code,
+// from genericUnwind(), or from FTL::callOperation().
+
+class State;
+
+class ExceptionHandlerManager {
+ WTF_MAKE_NONCOPYABLE(ExceptionHandlerManager);
+
+public:
+ ExceptionHandlerManager(State& state);
+
+ void addNewExit(uint32_t stackmapRecordIndex, size_t osrExitIndex);
+
+ // These functions only make sense to be called after we've generated the OSR
+ // exit thunks and allocated the OSR exit thunks' link buffer.
+ CodeLocationLabel getOrPutByIdCallOperationExceptionTarget(uint32_t stackmapRecordIndex);
+ CodeLocationLabel lazySlowPathExceptionTarget(uint32_t stackmapRecordIndex);
+
+ OSRExit* getByIdOSRExit(uint32_t stackmapRecordIndex);
+ OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSCall&);
+ OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSTailCall&);
+ OSRExit* getCallOSRExit(uint32_t stackmapRecordIndex, const JSCallVarargs&);
+
+ CallSiteIndex procureCallSiteIndex(uint32_t stackmapRecordIndex, CodeOrigin);
+ CallSiteIndex procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSCall&);
+ CallSiteIndex procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSTailCall&);
+ CallSiteIndex procureCallSiteIndex(uint32_t stackmapRecordIndex, const JSCallVarargs&);
+ OSRExit* jsCallOSRExit(uint32_t stackmapRecordIndex);
+
+private:
+ OSRExit* getCallOSRExitCommon(uint32_t stackmapRecordIndex);
+
+ State& m_state;
+ typedef HashMap<uint32_t, size_t, WTF::IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> RecordIndexToOSRExitIndexMap;
+ RecordIndexToOSRExitIndexMap m_map;
+};
+
+} } // namespace JSC::FTL
+
+#endif // ENABLE(FTL_JIT)
+
+#endif // FTLExceptionHandlerManager_h