diff --git a/JSTests/stress/regress-109263765.js b/JSTests/stress/regress-109263765.js new file mode 100644 index 000000000000..ce93004779d1 --- /dev/null +++ b/JSTests/stress/regress-109263765.js @@ -0,0 +1,16 @@ +//@requireOptions("--thresholdForFTLOptimizeSoon=0", "--validateAbstractInterpreterState=1") +function foo() { + let a = Object; + let b = Object; + let c = Array.prototype; + for (let i = 0; i < 10; i++) { + for (let j = 0; j < 100; j++) { + let xs = [0, 1]; + for (let x in xs) { } + } + } +} + +for (let i = 0; i < 100; i++) { + foo(); +} diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h index c2ba68b338cd..fc60638e4c19 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h +++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h @@ -4614,6 +4614,7 @@ bool AbstractInterpreter::executeEffects(unsigned clobberLimi } } m_state.setNonCellTypeForTupleNode(node, 0, SpecInt32Only); + clearForNode(node); break; } diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp index aea63acd6374..f9839aa36c95 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp @@ -501,7 +501,7 @@ class ArgumentsEliminationPhase : public Phase { // object's payload. Conservatively this means that the stack region doesn't get stored to. void eliminateCandidatesThatInterfere() { - performLivenessAnalysis(m_graph); + performGraphPackingAndLivenessAnalysis(m_graph); m_graph.initializeNodeOwners(); CombinedLiveness combinedLiveness(m_graph); diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp index 06d19d173973..630bdcacc7c0 100644 --- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp @@ -55,7 +55,7 @@ class CFAPhase : public Phase { { ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == SSA); ASSERT(m_graph.m_unificationState == GloballyUnified); - ASSERT(m_graph.m_refCountState == EverythingIsLive); + ASSERT(m_graph.m_refCountState == EverythingIsLive || Options::validateAbstractInterpreterState() && m_graph.m_refCountState == ExactRefCount); m_count = 0; diff --git a/Source/JavaScriptCore/dfg/DFGFlowMap.h b/Source/JavaScriptCore/dfg/DFGFlowMap.h index 45f6aac993b2..1313fb6b22e3 100644 --- a/Source/JavaScriptCore/dfg/DFGFlowMap.h +++ b/Source/JavaScriptCore/dfg/DFGFlowMap.h @@ -106,7 +106,14 @@ class FlowMap { ALWAYS_INLINE const T& at(unsigned nodeIndex, NodeFlowProjection::Kind kind) const { return const_cast(this)->at(nodeIndex, kind); } ALWAYS_INLINE const T& at(Node* node, NodeFlowProjection::Kind kind) const { return const_cast(this)->at(node, kind); } ALWAYS_INLINE const T& at(NodeFlowProjection projection) const { return const_cast(this)->at(projection); } - + + ALWAYS_INLINE void clear() + { + m_map.clear(); + m_shadowMap.clear(); + resize(); + } + private: Graph& m_graph; Vector m_map; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 70cb44c0c0ae..d8a2be72ab70 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -685,6 +685,11 @@ void Graph::packNodeIndices() m_nodes.packIndices(); } +void Graph::clearAbstractValues() +{ + m_abstractValuesCache->clear(); +} + void Graph::dethread() { if (m_form == LoadStore || m_form == SSA) diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index dc8cd8bc182e..3787764b0fd6 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -237,6 +237,7 @@ class Graph final : public virtual Scannable { unsigned maxNodeCount() const { return m_nodes.size(); } Node* nodeAt(unsigned index) const { return m_nodes[index]; } void packNodeIndices(); + void clearAbstractValues(); void dethread(); diff --git a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h index 3e836af1d611..21cf88691c9d 100644 --- a/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h +++ b/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.h @@ -88,7 +88,6 @@ class InPlaceAbstractState { ALWAYS_INLINE void clearForNode(NodeFlowProjection node) { - ASSERT(!node->isTuple()); AbstractValue& value = m_abstractValues.at(node); value.clear(); value.m_effectEpoch = m_effectEpoch; diff --git a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp index 6c6e2a45190c..2b0c9ab87940 100644 --- a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.cpp @@ -185,10 +185,12 @@ class LivenessAnalysisPhase : public Phase { } // anonymous namespace -bool performLivenessAnalysis(Graph& graph) +bool performGraphPackingAndLivenessAnalysis(Graph& graph) { graph.packNodeIndices(); - +#ifndef NDEBUG + graph.clearAbstractValues(); +#endif return runPhase(graph); } diff --git a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.h b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.h index 1d1f91471930..e8e060a05b6b 100644 --- a/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.h +++ b/Source/JavaScriptCore/dfg/DFGLivenessAnalysisPhase.h @@ -34,7 +34,7 @@ class Graph; // Computes BasicBlock::ssa->liveAtHead/liveAtTail. -bool performLivenessAnalysis(Graph&); +bool performGraphPackingAndLivenessAnalysis(Graph&); } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp index a49f12abc64d..e82396f2fe5a 100644 --- a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp @@ -817,7 +817,7 @@ class ObjectAllocationSinkingPhase : public Phase { m_graph.computeRefCounts(); m_graph.initializeNodeOwners(); m_graph.ensureSSADominators(); - performLivenessAnalysis(m_graph); + performGraphPackingAndLivenessAnalysis(m_graph); performOSRAvailabilityAnalysis(m_graph); m_combinedLiveness = CombinedLiveness(m_graph); diff --git a/Source/JavaScriptCore/dfg/DFGPlan.cpp b/Source/JavaScriptCore/dfg/DFGPlan.cpp index 1d4fa553ea77..86723329c96d 100644 --- a/Source/JavaScriptCore/dfg/DFGPlan.cpp +++ b/Source/JavaScriptCore/dfg/DFGPlan.cpp @@ -375,7 +375,7 @@ Plan::CompilationPath Plan::compileInThreadImpl() RUN_PHASE(performConstantHoisting); RUN_PHASE(performGlobalCSE); - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performCFA); RUN_PHASE(performConstantFolding); RUN_PHASE(performCFGSimplification); @@ -391,7 +391,7 @@ Plan::CompilationPath Plan::compileInThreadImpl() if (changed) { // State-at-tail and state-at-head will be invalid if we did strength reduction since // it might increase live ranges. - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performCFA); RUN_PHASE(performConstantFolding); RUN_PHASE(performCFGSimplification); @@ -402,7 +402,7 @@ Plan::CompilationPath Plan::compileInThreadImpl() // wrong with running LICM earlier, if we wanted to put other CFG transforms above this point. // Alternatively, we could run loop pre-header creation after SSA conversion - but if we did that // then we'd need to do some simple SSA fix-up. - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performCFA); RUN_PHASE(performLICM); @@ -413,7 +413,7 @@ Plan::CompilationPath Plan::compileInThreadImpl() // by IntegerRangeOptimization. // // Ideally, the dependencies should be explicit. See https://bugs.webkit.org/show_bug.cgi?id=157534. - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performIntegerRangeOptimization); RUN_PHASE(performCleanUp); @@ -424,14 +424,14 @@ Plan::CompilationPath Plan::compileInThreadImpl() // about code motion assumes that it's OK to insert GC points in random places. dfg.m_fixpointState = FixpointConverged; - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performCFA); RUN_PHASE(performGlobalStoreBarrierInsertion); RUN_PHASE(performStoreBarrierClustering); RUN_PHASE(performCleanUp); RUN_PHASE(performDCE); // We rely on this to kill dead code that won't be recognized as dead by B3. RUN_PHASE(performStackLayout); - RUN_PHASE(performLivenessAnalysis); + RUN_PHASE(performGraphPackingAndLivenessAnalysis); RUN_PHASE(performOSRAvailabilityAnalysis); if (FTL::canCompile(dfg) == FTL::CannotCompile) { diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp index 7fb4d49b46ea..7bd56ec81bb3 100644 --- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp +++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp @@ -41,6 +41,7 @@ #include "CallFrameShuffler.h" #include "ClonedArguments.h" #include "DFGAbstractInterpreterInlines.h" +#include "DFGCFAPhase.h" #include "DFGCapabilities.h" #include "DFGClobberize.h" #include "DFGDoesGC.h" @@ -166,8 +167,9 @@ class LowerDFGToB3 { , m_state(state.graph) , m_interpreter(state.graph, m_state) { - if (Options::validateAbstractInterpreterState()) { - performLivenessAnalysis(m_graph); + if (UNLIKELY(Options::validateAbstractInterpreterState())) { + performGraphPackingAndLivenessAnalysis(m_graph); + performCFA(m_graph); // We only use node liveness here, not combined liveness, as we only track // AI state for live nodes. @@ -615,7 +617,7 @@ class LowerDFGToB3 { continue; if (node->op() == CheckInBoundsInt52) continue; - if (node->op() == EnumeratorNextUpdateIndexAndMode) { + if (node->isTuple()) { ASSERT(m_interpreter.hasClearedAbstractState(node)); continue; } @@ -726,7 +728,7 @@ class LowerDFGToB3 { m_interpreter.startExecuting(); m_interpreter.executeKnownEdgeTypes(m_node); - if (Options::validateAbstractInterpreterState()) + if (UNLIKELY(Options::validateAbstractInterpreterState())) validateAIState(m_node); if constexpr (validateDFGDoesGC) {