Reveal array bounds checks in DFG IR
https://bugs.webkit.org/show_bug.cgi?id=125253
Reviewed by Oliver Hunt and Mark Hahnenberg.
In SSA mode, this reveals array bounds checks and the load of array length in DFG IR,
making this a candidate for LICM.
This also fixes a long-standing performance bug where the JSObject slow paths would
always create contiguous storage, rather than type-specialized storage, when doing a
"storage creating" storage, like:
var o = {};
o[0] = 42;
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
(JSC::exitKindIsCountable):
* bytecode/ExitKind.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::::executeEffects):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::permitsBoundsCheckLowering):
(JSC::DFG::ArrayMode::permitsBoundsCheckLowering):
* dfg/DFGArrayMode.h:
(JSC::DFG::ArrayMode::lengthNeedsStorage):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSSALoweringPhase.cpp: Added.
(JSC::DFG::SSALoweringPhase::SSALoweringPhase):
(JSC::DFG::SSALoweringPhase::run):
(JSC::DFG::SSALoweringPhase::handleNode):
(JSC::DFG::SSALoweringPhase::lowerBoundsCheck):
(JSC::DFG::performSSALowering):
* dfg/DFGSSALoweringPhase.h: Added.
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDoublePutByVal):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileContiguousPutByVal):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileCheckInBounds):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compilePutByVal):
(JSC::FTL::LowerDFGToLLVM::contiguousPutByValOutOfBounds):
* runtime/JSObject.cpp:
(JSC::JSObject::convertUndecidedForValue):
(JSC::JSObject::createInitialForValueAndSet):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
* runtime/JSObject.h:
* tests/stress/float32array-out-of-bounds.js: Added.
(make):
(foo):
(test):
* tests/stress/int32-object-out-of-bounds.js: Added.
(make):
(foo):
(test):
* tests/stress/int32-out-of-bounds.js: Added.
(foo):
(test):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160347 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index b81c440..b850daf 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -355,6 +355,9 @@
case GetArrayLength:
compileGetArrayLength();
break;
+ case CheckInBounds:
+ compileCheckInBounds();
+ break;
case GetByVal:
compileGetByVal();
break;
@@ -1475,6 +1478,13 @@
}
}
+ void compileCheckInBounds()
+ {
+ speculate(
+ OutOfBounds, noValue(), 0,
+ m_out.aboveOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
+ }
+
void compileGetByVal()
{
switch (m_node->arrayMode().type()) {
@@ -1487,11 +1497,6 @@
m_heaps.indexedInt32Properties : m_heaps.indexedContiguousProperties;
if (m_node->arrayMode().isInBounds()) {
- speculate(
- OutOfBounds, noValue(), 0,
- m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
-
LValue result = m_out.load64(baseIndex(heap, storage, index, m_node->child2()));
speculate(LoadFromHole, noValue(), 0, m_out.isZero64(result));
setJSValue(result);
@@ -1532,11 +1537,6 @@
IndexedAbstractHeap& heap = m_heaps.indexedDoubleProperties;
if (m_node->arrayMode().isInBounds()) {
- speculate(
- OutOfBounds, noValue(), 0,
- m_out.aboveOrEqual(
- index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
-
LValue result = m_out.loadDouble(
baseIndex(heap, storage, index, m_node->child2()));
@@ -1600,11 +1600,6 @@
TypedArrayType type = m_node->arrayMode().typedArrayType();
if (isTypedView(type)) {
- speculate(
- OutOfBounds, noValue(), 0,
- m_out.aboveOrEqual(
- index, typedArrayLength(m_node->child1(), m_node->arrayMode())));
-
TypedPointer pointer = TypedPointer(
m_heaps.typedArrayProperties,
m_out.add(
@@ -1792,14 +1787,6 @@
TypedArrayType type = m_node->arrayMode().typedArrayType();
if (isTypedView(type)) {
- if (m_node->op() != PutByValAlias) {
- speculate(
- OutOfBounds, noValue(), 0,
- m_out.aboveOrEqual(
- index,
- typedArrayLength(child1, m_node->arrayMode(), base)));
- }
-
TypedPointer pointer = TypedPointer(
m_heaps.typedArrayProperties,
m_out.add(
@@ -3085,15 +3072,12 @@
template<typename FunctionType>
void contiguousPutByValOutOfBounds(
- FunctionType slowPathFunction,
- LValue base, LValue storage, LValue index, LValue value,
+ FunctionType slowPathFunction, LValue base, LValue storage, LValue index, LValue value,
LBasicBlock continuation)
{
LValue isNotInBounds = m_out.aboveOrEqual(
index, m_out.load32(storage, m_heaps.Butterfly_publicLength));
- if (m_node->arrayMode().isInBounds())
- speculate(StoreToHoleOrOutOfBounds, noValue(), 0, isNotInBounds);
- else {
+ if (!m_node->arrayMode().isInBounds()) {
LBasicBlock notInBoundsCase =
FTL_NEW_BLOCK(m_out, ("PutByVal not in bounds"));
LBasicBlock performStore =