Title: [264049] trunk
Revision
264049
Author
[email protected]
Date
2020-07-07 17:32:35 -0700 (Tue, 07 Jul 2020)

Log Message

Bytecode UseDef should be aware of checkpoints
https://bugs.webkit.org/show_bug.cgi?id=213566

Reviewed by Saam Barati.

JSTests:

* stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js: Added.
(foo):

Source/_javascript_Core:

Previously, we tried to solve teaching DFG about uses and defs of
locals across checkpoints by asking what locals were def'd at some
checkpoint. However, this was subtly wrong because we couldn't
report any uses at subsequent checkpoints so DFG thought the
local was dead immediately after its birth.

This patch reverts that change and instead teaches BytecodeUseDef
about checkpoints. Right now, BytecodeUseDef only knows about
locals at checkpoints but in the future we may teach it about tmps
at well.

Since the vectors containing our liveness bitmaps were already
sparse (they are indexed by the bytecode offset) we can reuse the
gaps to hold our checkpoint liveness information. To make sure we
don't overlap between the next bytecode and a checkpoint for the
current bytecode there is now a static assert that the length of
the bytecode is greater than the number of checkpoints. This
assumption is already true for existing bytecodes with checkpoints (and
likely to be true for future ones anyway).

Many of the BytecodeLivenessPropegation functions have been
renamed to reflect that they operate over the full instruction,
including checkpoints, rather than just the BytecodeIndex passed.

Lastly, this patch makes a speculative fix to forAllKilledOperands where we
wouldn't report that all tmps die at the end of each bytecode. I can't think
of a case where this would break things but it's probably good hygiene.

* bytecode/BytecodeGeneratorification.cpp:
(JSC::GeneratorLivenessAnalysis::run):
* bytecode/BytecodeIndex.h:
(JSC::BytecodeIndex::BytecodeIndex):
(JSC::BytecodeIndex::checkpoint const):
(JSC::BytecodeIndex::withCheckpoint const):
(JSC::BytecodeIndex::pack):
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
(JSC::BytecodeLivenessAnalysis::dumpResults):
(JSC::tmpLivenessForCheckpoint):
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeIndex): Deleted.
(JSC::livenessForCheckpoint): Deleted.
* bytecode/BytecodeLivenessAnalysis.h:
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtInstruction):
* bytecode/BytecodeLivenessAnalysisInlines.h:
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexDef):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUse):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUseInExceptionHandler):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndex):
(JSC::BytecodeLivenessPropagation::stepOverInstruction):
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForInstruction):
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForBlock):
(JSC::BytecodeLivenessPropagation::getLivenessInfoAtInstruction):
(JSC::BytecodeLivenessPropagation::stepOverInstructionDef): Deleted.
(JSC::BytecodeLivenessPropagation::stepOverInstructionUse): Deleted.
(JSC::BytecodeLivenessPropagation::stepOverInstructionUseInExceptionHandler): Deleted.
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForBytecodeIndex): Deleted.
(JSC::BytecodeLivenessPropagation::getLivenessInfoAtBytecodeIndex): Deleted.
* bytecode/BytecodeUseDef.cpp:
(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeIndex):
(JSC::computeDefsForBytecodeIndex):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::ensureCatchLivenessIsComputedForBytecodeIndexSlow):
(JSC::CodeBlock::validate):
* bytecode/FullBytecodeLiveness.h:
(JSC::FullBytecodeLiveness::getLiveness const):
(JSC::FullBytecodeLiveness::toIndex):
* bytecode/Instruction.h:
(JSC::BaseInstruction::numberOfCheckpoints const):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::ForInContext::finalize):
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllKilledOperands):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::isLiveInBytecode):
* dfg/DFGGraph.h:
* dfg/DFGMovHintRemovalPhase.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::cleanMustHandleValuesIfNecessary):
* generator/Opcode.rb:
* generator/Section.rb:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (264048 => 264049)


--- trunk/JSTests/ChangeLog	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/JSTests/ChangeLog	2020-07-08 00:32:35 UTC (rev 264049)
@@ -1,3 +1,13 @@
+2020-07-07  Keith Miller  <[email protected]>
+
+        Bytecode UseDef should be aware of checkpoints
+        https://bugs.webkit.org/show_bug.cgi?id=213566
+
+        Reviewed by Saam Barati.
+
+        * stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js: Added.
+        (foo):
+
 2020-07-04  Alexey Shvayka  <[email protected]>
 
         %TypedArray%.prototype.{indexOf,lastIndexOf} are not spec-perfect

Added: trunk/JSTests/stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js (0 => 264049)


--- trunk/JSTests/stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js	                        (rev 0)
+++ trunk/JSTests/stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js	2020-07-08 00:32:35 UTC (rev 264049)
@@ -0,0 +1,14 @@
+//@ requireOptions("--jitPolicyScale=0", "--validateFTLOSRExitLiveness=1")
+
+function foo() {
+  for (let i=0; i<100; i++) {
+    let u8 = new Uint8Array(4);
+    for (let q of u8) {}
+    let u32 = new Uint32Array(2);
+    for (let q of u32) {}
+  }
+}
+
+for (let i=0; i<100; i++) {
+  foo();
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (264048 => 264049)


--- trunk/Source/_javascript_Core/ChangeLog	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-07-08 00:32:35 UTC (rev 264049)
@@ -1,3 +1,94 @@
+2020-07-07  Keith Miller  <[email protected]>
+
+        Bytecode UseDef should be aware of checkpoints
+        https://bugs.webkit.org/show_bug.cgi?id=213566
+
+        Reviewed by Saam Barati.
+
+        Previously, we tried to solve teaching DFG about uses and defs of
+        locals across checkpoints by asking what locals were def'd at some
+        checkpoint. However, this was subtly wrong because we couldn't
+        report any uses at subsequent checkpoints so DFG thought the
+        local was dead immediately after its birth.
+
+        This patch reverts that change and instead teaches BytecodeUseDef
+        about checkpoints. Right now, BytecodeUseDef only knows about
+        locals at checkpoints but in the future we may teach it about tmps
+        at well.
+
+        Since the vectors containing our liveness bitmaps were already
+        sparse (they are indexed by the bytecode offset) we can reuse the
+        gaps to hold our checkpoint liveness information. To make sure we
+        don't overlap between the next bytecode and a checkpoint for the
+        current bytecode there is now a static assert that the length of
+        the bytecode is greater than the number of checkpoints. This
+        assumption is already true for existing bytecodes with checkpoints (and
+        likely to be true for future ones anyway).
+
+        Many of the BytecodeLivenessPropegation functions have been
+        renamed to reflect that they operate over the full instruction,
+        including checkpoints, rather than just the BytecodeIndex passed.
+
+        Lastly, this patch makes a speculative fix to forAllKilledOperands where we
+        wouldn't report that all tmps die at the end of each bytecode. I can't think
+        of a case where this would break things but it's probably good hygiene.
+
+        * bytecode/BytecodeGeneratorification.cpp:
+        (JSC::GeneratorLivenessAnalysis::run):
+        * bytecode/BytecodeIndex.h:
+        (JSC::BytecodeIndex::BytecodeIndex):
+        (JSC::BytecodeIndex::checkpoint const):
+        (JSC::BytecodeIndex::withCheckpoint const):
+        (JSC::BytecodeIndex::pack):
+        * bytecode/BytecodeLivenessAnalysis.cpp:
+        (JSC::BytecodeLivenessAnalysis::computeFullLiveness):
+        (JSC::BytecodeLivenessAnalysis::dumpResults):
+        (JSC::tmpLivenessForCheckpoint):
+        (JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeIndex): Deleted.
+        (JSC::livenessForCheckpoint): Deleted.
+        * bytecode/BytecodeLivenessAnalysis.h:
+        (JSC::BytecodeLivenessAnalysis::getLivenessInfoAtInstruction):
+        * bytecode/BytecodeLivenessAnalysisInlines.h:
+        (JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexDef):
+        (JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUse):
+        (JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUseInExceptionHandler):
+        (JSC::BytecodeLivenessPropagation::stepOverBytecodeIndex):
+        (JSC::BytecodeLivenessPropagation::stepOverInstruction):
+        (JSC::BytecodeLivenessPropagation::computeLocalLivenessForInstruction):
+        (JSC::BytecodeLivenessPropagation::computeLocalLivenessForBlock):
+        (JSC::BytecodeLivenessPropagation::getLivenessInfoAtInstruction):
+        (JSC::BytecodeLivenessPropagation::stepOverInstructionDef): Deleted.
+        (JSC::BytecodeLivenessPropagation::stepOverInstructionUse): Deleted.
+        (JSC::BytecodeLivenessPropagation::stepOverInstructionUseInExceptionHandler): Deleted.
+        (JSC::BytecodeLivenessPropagation::computeLocalLivenessForBytecodeIndex): Deleted.
+        (JSC::BytecodeLivenessPropagation::getLivenessInfoAtBytecodeIndex): Deleted.
+        * bytecode/BytecodeUseDef.cpp:
+        (JSC::computeUsesForBytecodeIndexImpl):
+        (JSC::computeDefsForBytecodeIndexImpl):
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeIndex):
+        (JSC::computeDefsForBytecodeIndex):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::ensureCatchLivenessIsComputedForBytecodeIndexSlow):
+        (JSC::CodeBlock::validate):
+        * bytecode/FullBytecodeLiveness.h:
+        (JSC::FullBytecodeLiveness::getLiveness const):
+        (JSC::FullBytecodeLiveness::toIndex):
+        * bytecode/Instruction.h:
+        (JSC::BaseInstruction::numberOfCheckpoints const):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::ForInContext::finalize):
+        * dfg/DFGForAllKills.h:
+        (JSC::DFG::forAllKilledOperands):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::isLiveInBytecode):
+        * dfg/DFGGraph.h:
+        * dfg/DFGMovHintRemovalPhase.cpp:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::cleanMustHandleValuesIfNecessary):
+        * generator/Opcode.rb:
+        * generator/Section.rb:
+
 2020-07-06  Geoffrey Garen  <[email protected]>
 
         callOnMainThread should use the same queue as RunLoop::dispatch

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeGeneratorification.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -194,7 +194,7 @@
         runLivenessFixpoint(codeBlock, instructions, m_generatorification.graph());
 
         for (YieldData& data : m_generatorification.yields())
-            data.liveness = getLivenessInfoAtBytecodeIndex(codeBlock, instructions, m_generatorification.graph(), BytecodeIndex(m_generatorification.instructions().at(data.point).next().offset()));
+            data.liveness = getLivenessInfoAtInstruction(codeBlock, instructions, m_generatorification.graph(), BytecodeIndex(m_generatorification.instructions().at(data.point).next().offset()));
     }
 
 private:

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeIndex.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeIndex.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeIndex.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -34,6 +34,9 @@
 
 namespace JSC {
 
+using Checkpoint = uint8_t;
+static constexpr Checkpoint noCheckpoints = 0;
+
 class BytecodeIndex {
 public:
     BytecodeIndex() = default;
@@ -42,7 +45,7 @@
     {
     }
 
-    explicit BytecodeIndex(uint32_t bytecodeOffset, uint8_t checkpoint = 0)
+    explicit BytecodeIndex(uint32_t bytecodeOffset, Checkpoint checkpoint = noCheckpoints)
         : m_packedBits(pack(bytecodeOffset, checkpoint))
     {
         ASSERT(*this);
@@ -54,7 +57,7 @@
     static constexpr uint32_t checkpointShift = WTF::getMSBSetConstexpr(numberOfCheckpoints);
 
     uint32_t offset() const { return m_packedBits >> checkpointShift; }
-    uint8_t checkpoint() const { return m_packedBits & checkpointMask; }
+    Checkpoint checkpoint() const { return m_packedBits & checkpointMask; }
     uint32_t asBits() const { return m_packedBits; }
 
     unsigned hash() const { return WTF::intHash(m_packedBits); }
@@ -62,7 +65,7 @@
     bool isHashTableDeletedValue() const { return *this == deletedValue(); }
 
     static BytecodeIndex fromBits(uint32_t bits);
-    BytecodeIndex withCheckpoint(unsigned checkpoint) const { return BytecodeIndex(offset(), checkpoint); }
+    BytecodeIndex withCheckpoint(Checkpoint checkpoint) const { return BytecodeIndex(offset(), checkpoint); }
 
     // Comparison operators.
     explicit operator bool() const { return m_packedBits != invalidOffset && m_packedBits != deletedValue().offset(); }
@@ -80,12 +83,12 @@
 private:
     static constexpr uint32_t invalidOffset = std::numeric_limits<uint32_t>::max();
 
-    static uint32_t pack(uint32_t bytecodeIndex, uint8_t checkpoint);
+    static uint32_t pack(uint32_t bytecodeIndex, Checkpoint);
 
     uint32_t m_packedBits { invalidOffset };
 };
 
-inline uint32_t BytecodeIndex::pack(uint32_t bytecodeIndex, uint8_t checkpoint)
+inline uint32_t BytecodeIndex::pack(uint32_t bytecodeIndex, Checkpoint checkpoint)
 {
     ASSERT(checkpoint < numberOfCheckpoints);
     ASSERT((bytecodeIndex << checkpointShift) >> checkpointShift == bytecodeIndex);

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -31,7 +31,6 @@
 #include "CodeBlock.h"
 #include "FullBytecodeLiveness.h"
 #include "JSCJSValueInlines.h"
-#include <wtf/Scope.h>
 
 namespace JSC {
 
@@ -44,29 +43,13 @@
         dumpResults(codeBlock);
 }
 
-void BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeIndex(CodeBlock* codeBlock, BytecodeIndex bytecodeIndex, FastBitVector& result)
-{
-    BytecodeBasicBlock* block = m_graph.findBasicBlockForBytecodeOffset(bytecodeIndex.offset());
-    ASSERT(block);
-    ASSERT(!block->isEntryBlock());
-    ASSERT(!block->isExitBlock());
-    result.resize(block->out().numBits());
-    computeLocalLivenessForBytecodeIndex(codeBlock, codeBlock->instructions(), m_graph, *block, bytecodeIndex, result);
-}
-
-FastBitVector BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeIndex(CodeBlock* codeBlock, BytecodeIndex bytecodeIndex)
-{
-    FastBitVector out;
-    getLivenessInfoAtBytecodeIndex(codeBlock, bytecodeIndex, out);
-    return out;
-}
-
 void BytecodeLivenessAnalysis::computeFullLiveness(CodeBlock* codeBlock, FullBytecodeLiveness& result)
 {
     FastBitVector out;
 
-    result.m_beforeUseVector.resize(codeBlock->instructions().size());
-    result.m_afterUseVector.resize(codeBlock->instructions().size());
+    size_t size = codeBlock->instructions().size();
+    result.m_usesBefore.resize(size);
+    result.m_usesAfter.resize(size);
     
     for (BytecodeBasicBlock& block : m_graph.basicBlocksInReverseOrder()) {
         if (block.isEntryBlock() || block.isExitBlock())
@@ -73,7 +56,7 @@
             continue;
         
         out = block.out();
-        
+
         auto use = [&] (unsigned bitIndex) {
             // This is the use functor, so we set the bit.
             out[bitIndex] = true;
@@ -89,12 +72,17 @@
         for (unsigned i = block.delta().size(); i--;) {
             cursor -= block.delta()[i];
             BytecodeIndex bytecodeIndex = BytecodeIndex(block.leaderOffset() + cursor);
+            auto instruction = instructions.at(bytecodeIndex);
+            for (Checkpoint checkpoint = instruction->numberOfCheckpoints(); checkpoint--;) {
+                ASSERT(checkpoint < instruction->size());
+                bytecodeIndex = bytecodeIndex.withCheckpoint(checkpoint);
 
-            stepOverInstructionDef(codeBlock, instructions, m_graph, bytecodeIndex, def);
-            stepOverInstructionUseInExceptionHandler(codeBlock, instructions, m_graph, bytecodeIndex, use);
-            result.m_afterUseVector[bytecodeIndex.offset()] = out; // AfterUse point.
-            stepOverInstructionUse(codeBlock, instructions, m_graph, bytecodeIndex, use);
-            result.m_beforeUseVector[bytecodeIndex.offset()] = out; // BeforeUse point.
+                stepOverBytecodeIndexDef(codeBlock, instructions, m_graph, bytecodeIndex, def);
+                stepOverBytecodeIndexUseInExceptionHandler(codeBlock, instructions, m_graph, bytecodeIndex, use);
+                result.m_usesAfter[result.toIndex(bytecodeIndex)] = out; // AfterUse point.
+                stepOverBytecodeIndexUse(codeBlock, instructions, m_graph, bytecodeIndex, use);
+                result.m_usesBefore[result.toIndex(bytecodeIndex)] = out; // BeforeUse point.
+            }
         }
     }
 }
@@ -150,7 +138,7 @@
             const auto currentInstruction = instructions.at(bytecodeOffset);
 
             dataLogF("Live variables:");
-            FastBitVector liveBefore = getLivenessInfoAtBytecodeIndex(codeBlock, BytecodeIndex(bytecodeOffset));
+            FastBitVector liveBefore = getLivenessInfoAtInstruction(codeBlock, BytecodeIndex(bytecodeOffset));
             dumpBitVector(liveBefore);
             dataLogF("\n");
             codeBlock->dumpBytecode(WTF::dataFile(), currentInstruction);
@@ -176,15 +164,11 @@
         return static_cast<IntType2>(v1) == static_cast<IntType2>(v2);
 }
 
-Vector<Operand, maxNumCheckpointTmps> livenessForCheckpoint(const CodeBlock& codeBlock, BytecodeIndex bytecodeIndex)
+Bitmap<maxNumCheckpointTmps> tmpLivenessForCheckpoint(const CodeBlock& codeBlock, BytecodeIndex bytecodeIndex)
 {
-    Vector<Operand, maxNumCheckpointTmps> result;
-    uint8_t checkpoint = bytecodeIndex.checkpoint();
+    Bitmap<maxNumCheckpointTmps> result;
+    Checkpoint checkpoint = bytecodeIndex.checkpoint();
 
-    auto scopeExit = makeScopeExit([&] {
-        ASSERT(result.size() <= maxNumCheckpointTmps);
-    });
-
     if (!checkpoint)
         return result;
 
@@ -195,16 +179,14 @@
         static_assert(enumValuesEqualAsIntegral(OpCallVarargs::makeCall, OpTailCallVarargs::makeCall) && enumValuesEqualAsIntegral(OpCallVarargs::argCountIncludingThis, OpTailCallVarargs::argCountIncludingThis));
         static_assert(enumValuesEqualAsIntegral(OpCallVarargs::makeCall, OpConstructVarargs::makeCall) && enumValuesEqualAsIntegral(OpCallVarargs::argCountIncludingThis, OpConstructVarargs::argCountIncludingThis));
         if (checkpoint == OpCallVarargs::makeCall)
-            result.append(Operand::tmp(OpCallVarargs::argCountIncludingThis));
+            result.set(OpCallVarargs::argCountIncludingThis);
         return result;
     }
     case op_iterator_open: {
-        if (checkpoint == OpIteratorOpen::getNext)
-            result.append(codeBlock.instructions().at(bytecodeIndex)->as<OpIteratorOpen>().m_iterator);
         return result;
     }
     case op_iterator_next: {
-        result.append(Operand::tmp(OpIteratorNext::nextResult));
+        result.set(OpIteratorNext::nextResult);
         return result;
     }
     default:

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysis.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -51,26 +51,26 @@
 class BytecodeLivenessPropagation {
 public:
     template<typename CodeBlockType, typename UseFunctor>
-    static void stepOverInstructionUse(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&);
+    static void stepOverBytecodeIndexUse(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&);
     template<typename CodeBlockType, typename UseFunctor>
-    static void stepOverInstructionUseInExceptionHandler(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&);
+    static void stepOverBytecodeIndexUseInExceptionHandler(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&);
     template<typename CodeBlockType, typename DefFunctor>
-    static void stepOverInstructionDef(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const DefFunctor&);
+    static void stepOverBytecodeIndexDef(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const DefFunctor&);
 
     template<typename CodeBlockType, typename UseFunctor, typename DefFunctor>
-    static void stepOverInstruction(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&, const DefFunctor&);
+    static void stepOverBytecodeIndex(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, const UseFunctor&, const DefFunctor&);
 
     template<typename CodeBlockType>
     static void stepOverInstruction(CodeBlockType*, const InstructionStream&, BytecodeGraph&, BytecodeIndex, FastBitVector& out);
 
     template<typename CodeBlockType, typename Instructions>
-    static bool computeLocalLivenessForBytecodeIndex(CodeBlockType*, const Instructions&, BytecodeGraph&, BytecodeBasicBlock&, BytecodeIndex, FastBitVector& result);
+    static bool computeLocalLivenessForInstruction(CodeBlockType*, const Instructions&, BytecodeGraph&, BytecodeBasicBlock&, BytecodeIndex, FastBitVector& result);
 
     template<typename CodeBlockType, typename Instructions>
     static bool computeLocalLivenessForBlock(CodeBlockType*, const Instructions&, BytecodeGraph&, BytecodeBasicBlock&);
 
     template<typename CodeBlockType, typename Instructions>
-    static FastBitVector getLivenessInfoAtBytecodeIndex(CodeBlockType*, const Instructions&, BytecodeGraph&, BytecodeIndex);
+    static FastBitVector getLivenessInfoAtInstruction(CodeBlockType*, const Instructions&, BytecodeGraph&, BytecodeIndex);
 
     template<typename CodeBlockType, typename Instructions>
     static void runLivenessFixpoint(CodeBlockType*, const Instructions&, BytecodeGraph&);
@@ -83,7 +83,7 @@
     friend class BytecodeLivenessPropagation;
     BytecodeLivenessAnalysis(CodeBlock*);
     
-    FastBitVector getLivenessInfoAtBytecodeIndex(CodeBlock*, BytecodeIndex);
+    FastBitVector getLivenessInfoAtInstruction(CodeBlock* codeBlock, BytecodeIndex bytecodeIndex) { return BytecodeLivenessPropagation::getLivenessInfoAtInstruction(codeBlock, codeBlock->instructions(), m_graph, bytecodeIndex); }
     
     void computeFullLiveness(CodeBlock*, FullBytecodeLiveness& result);
 
@@ -92,12 +92,10 @@
 private:
     void dumpResults(CodeBlock*);
 
-    void getLivenessInfoAtBytecodeIndex(CodeBlock*, BytecodeIndex, FastBitVector&);
-
     BytecodeGraph m_graph;
 };
 
-Vector<Operand, maxNumCheckpointTmps> livenessForCheckpoint(const CodeBlock&, BytecodeIndex);
+Bitmap<maxNumCheckpointTmps> tmpLivenessForCheckpoint(const CodeBlock&, BytecodeIndex);
 
 inline bool operandIsAlwaysLive(int operand);
 inline bool operandThatIsNotAlwaysLiveIsLive(const FastBitVector& out, int operand);

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysisInlines.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysisInlines.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeLivenessAnalysisInlines.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -27,6 +27,7 @@
 
 #include "BytecodeGraph.h"
 #include "BytecodeLivenessAnalysis.h"
+#include "BytecodeUseDef.h"
 #include "CodeBlock.h"
 #include "InterpreterInlines.h"
 
@@ -58,11 +59,11 @@
 }
 
 template<typename CodeBlockType, typename DefFunctor>
-inline void BytecodeLivenessPropagation::stepOverInstructionDef(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const DefFunctor& def)
+inline void BytecodeLivenessPropagation::stepOverBytecodeIndexDef(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const DefFunctor& def)
 {
     auto* instruction = instructions.at(bytecodeIndex).ptr();
     computeDefsForBytecodeIndex(
-        codeBlock, instruction,
+        codeBlock, instruction, bytecodeIndex.checkpoint(),
         [&] (VirtualRegister operand) {
             if (isValidRegisterForLiveness(operand))
                 def(operand.toLocal());
@@ -70,11 +71,11 @@
 }
 
 template<typename CodeBlockType, typename UseFunctor>
-inline void BytecodeLivenessPropagation::stepOverInstructionUse(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const UseFunctor& use)
+inline void BytecodeLivenessPropagation::stepOverBytecodeIndexUse(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const UseFunctor& use)
 {
     auto* instruction = instructions.at(bytecodeIndex).ptr();
     computeUsesForBytecodeIndex(
-        codeBlock, instruction,
+        codeBlock, instruction, bytecodeIndex.checkpoint(),
         [&] (VirtualRegister operand) {
             if (isValidRegisterForLiveness(operand))
                 use(operand.toLocal());
@@ -82,10 +83,10 @@
 }
 
 template<typename CodeBlockType, typename UseFunctor>
-inline void BytecodeLivenessPropagation::stepOverInstructionUseInExceptionHandler(CodeBlockType* codeBlock, const InstructionStream&, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use)
+inline void BytecodeLivenessPropagation::stepOverBytecodeIndexUseInExceptionHandler(CodeBlockType* codeBlock, const InstructionStream&, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use)
 {
     // If we have an exception handler, we want the live-in variables of the 
-    // exception handler block to be included in the live-in of this particular bytecode.
+    // exception handler block to be included in the live-in of this particular BytecodeIndex.
     if (auto* handler = codeBlock->handlerForBytecodeIndex(bytecodeIndex)) {
         BytecodeBasicBlock* handlerBlock = graph.findBasicBlockWithLeaderOffset(handler->target);
         ASSERT(handlerBlock);
@@ -96,9 +97,9 @@
 // Simplified interface to bytecode use/def, which determines defs first and then uses, and includes
 // exception handlers in the uses.
 template<typename CodeBlockType, typename UseFunctor, typename DefFunctor>
-inline void BytecodeLivenessPropagation::stepOverInstruction(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use, const DefFunctor& def)
+inline void BytecodeLivenessPropagation::stepOverBytecodeIndex(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use, const DefFunctor& def)
 {
-    // This abstractly execute the instruction in reverse. Instructions logically first use operands and
+    // This abstractly executes the BytecodeIndex in reverse. Instructions logically first use operands and
     // then define operands. This logical ordering is necessary for operations that use and def the same
     // operand, like:
     //
@@ -113,31 +114,35 @@
     // uses before defs, then the add operation above would appear to not have loc1 live, since we'd
     // first add it to the out set (the use), and then we'd remove it (the def).
 
-    stepOverInstructionDef(codeBlock, instructions, graph, bytecodeIndex, def);
-    stepOverInstructionUseInExceptionHandler(codeBlock, instructions, graph, bytecodeIndex, use);
-    stepOverInstructionUse(codeBlock, instructions, graph, bytecodeIndex, use);
+    stepOverBytecodeIndexDef(codeBlock, instructions, graph, bytecodeIndex, def);
+    stepOverBytecodeIndexUseInExceptionHandler(codeBlock, instructions, graph, bytecodeIndex, use);
+    stepOverBytecodeIndexUse(codeBlock, instructions, graph, bytecodeIndex, use);
 }
 
 template<typename CodeBlockType>
 inline void BytecodeLivenessPropagation::stepOverInstruction(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, FastBitVector& out)
 {
-    stepOverInstruction(
-        codeBlock, instructions, graph, bytecodeIndex,
-        [&] (unsigned bitIndex) {
-            // This is the use functor, so we set the bit.
-            out[bitIndex] = true;
-        },
-        [&] (unsigned bitIndex) {
-            // This is the def functor, so we clear the bit.
-            out[bitIndex] = false;
-        });
+    auto numberOfCheckpoints = instructions.at(bytecodeIndex)->numberOfCheckpoints();
+    for (Checkpoint checkpoint = numberOfCheckpoints; checkpoint--;) {
+        stepOverBytecodeIndex(
+            codeBlock, instructions, graph, bytecodeIndex.withCheckpoint(checkpoint),
+            [&] (unsigned bitIndex) {
+                // This is the use functor, so we set the bit.
+                out[bitIndex] = true;
+            },
+            [&] (unsigned bitIndex) {
+                // This is the def functor, so we clear the bit.
+                out[bitIndex] = false;
+            });
+    }
 }
 
 template<typename CodeBlockType, typename Instructions>
-inline bool BytecodeLivenessPropagation::computeLocalLivenessForBytecodeIndex(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeBasicBlock& block, BytecodeIndex targetIndex, FastBitVector& result)
+inline bool BytecodeLivenessPropagation::computeLocalLivenessForInstruction(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeBasicBlock& block, BytecodeIndex targetIndex, FastBitVector& result)
 {
     ASSERT(!block.isExitBlock());
     ASSERT(!block.isEntryBlock());
+    ASSERT_WITH_MESSAGE(!targetIndex.checkpoint(), "computeLocalLivenessForInstruction can't be used to ask questions about checkpoints");
 
     FastBitVector out = block.out();
 
@@ -158,12 +163,13 @@
 {
     if (block.isExitBlock() || block.isEntryBlock())
         return false;
-    return computeLocalLivenessForBytecodeIndex(codeBlock, instructions, graph, block, BytecodeIndex(block.leaderOffset()), block.in());
+    return computeLocalLivenessForInstruction(codeBlock, instructions, graph, block, BytecodeIndex(block.leaderOffset()), block.in());
 }
 
 template<typename CodeBlockType, typename Instructions>
-inline FastBitVector BytecodeLivenessPropagation::getLivenessInfoAtBytecodeIndex(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex)
+inline FastBitVector BytecodeLivenessPropagation::getLivenessInfoAtInstruction(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex)
 {
+    ASSERT_WITH_MESSAGE(!bytecodeIndex.checkpoint(), "getLivenessInfoAtInstruction can't be used to ask questions about checkpoints");
     BytecodeBasicBlock* block = graph.findBasicBlockForBytecodeOffset(bytecodeIndex.offset());
     ASSERT(block);
     ASSERT(!block->isEntryBlock());
@@ -170,7 +176,7 @@
     ASSERT(!block->isExitBlock());
     FastBitVector out;
     out.resize(block->out().numBits());
-    computeLocalLivenessForBytecodeIndex(codeBlock, instructions, graph, *block, bytecodeIndex, out);
+    computeLocalLivenessForInstruction(codeBlock, instructions, graph, *block, bytecodeIndex, out);
     return out;
 }
 

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -33,6 +33,7 @@
 
 #define USES_OR_DEFS(__opcode, ...) \
     case __opcode::opcodeID: { \
+        static_assert(__opcode::opcodeID >= NUMBER_OF_BYTECODE_WITH_CHECKPOINTS, "Don't use this macro for bytecodes that have checkpoints."); \
         auto __bytecode = instruction->as<__opcode>(); \
         WTF_LAZY_FOR_EACH_TERM(CALL_FUNCTOR, __VA_ARGS__) \
         return; \
@@ -41,17 +42,18 @@
 #define USES USES_OR_DEFS
 #define DEFS USES_OR_DEFS
 
-void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instruction* instruction, Checkpoint checkpoint, const ScopedLambda<void(VirtualRegister)>& functor)
 {
     OpcodeID opcodeID = instruction->opcodeID();
 
-    auto handleNewArrayLike = [&](auto op) {
+
+    auto handleNewArrayLike = [&] (auto op) {
         int base = op.m_argv.offset();
         for (int i = 0; i < static_cast<int>(op.m_argc); i++)
             functor(VirtualRegister { base - i });
     };
 
-    auto handleOpCallLike = [&](auto op) {
+    auto handleOpCallLike = [&] (auto op) {
         functor(op.m_callee);
         int lastArg = -static_cast<int>(op.m_argv) + CallFrame::thisArgumentOffset();
         for (int i = 0; i < static_cast<int>(op.m_argc); i++)
@@ -61,6 +63,15 @@
         return;
     };
 
+    auto useAtEachCheckpoint = [&] (auto... virtualRegisters) {
+        (functor(virtualRegisters), ...);
+    };
+
+    auto useAtEachCheckpointStartingWith = [&] (Checkpoint firstUse, auto... virtualRegisters) {
+        if (checkpoint >= firstUse)
+            (functor(virtualRegisters), ...);
+    };
+
     switch (opcodeID) {
     case op_wide16:
     case op_wide32:
@@ -250,10 +261,23 @@
     USES(OpHasStructureProperty, base, property, enumerator)
     USES(OpHasOwnStructureProperty, base, property, enumerator)
     USES(OpInStructureProperty, base, property, enumerator)
-    USES(OpConstructVarargs, callee, thisValue, arguments)
-    USES(OpCallVarargs, callee, thisValue, arguments)
-    USES(OpTailCallVarargs, callee, thisValue, arguments)
 
+    case op_call_varargs: {
+        auto bytecode = instruction->as<OpCallVarargs>();
+        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
+        return;
+    }
+    case op_tail_call_varargs: {
+        auto bytecode = instruction->as<OpTailCallVarargs>();
+        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
+        return;
+    }
+    case op_construct_varargs: {
+        auto bytecode = instruction->as<OpConstructVarargs>();
+        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
+        return;
+    }
+
     USES(OpGetDirectPname, base, property, index, enumerator)
 
     USES(OpSwitchString, scrutinee)
@@ -265,9 +289,20 @@
 
     USES(OpYield, generator, argument)
 
-    USES(OpIteratorOpen, symbolIterator, iterable)
-    USES(OpIteratorNext, iterator, next, iterable)
+    case op_iterator_open: {
+        auto bytecode = instruction->as<OpIteratorOpen>();
+        useAtEachCheckpointStartingWith(OpIteratorOpen::symbolCall, bytecode.m_symbolIterator, bytecode.m_iterable);
+        useAtEachCheckpointStartingWith(OpIteratorOpen::getNext, bytecode.m_iterator);
+        return;
+    }
 
+    case op_iterator_next: {
+        auto bytecode = instruction->as<OpIteratorNext>();
+        useAtEachCheckpoint(bytecode.m_iterator);
+        useAtEachCheckpointStartingWith(OpIteratorNext::computeNext, bytecode.m_next, bytecode.m_iterable);
+        return;
+    }
+
     case op_new_array_with_spread:
         handleNewArrayLike(instruction->as<OpNewArrayWithSpread>());
         return;
@@ -302,8 +337,14 @@
     }
 }
 
-void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instruction, Checkpoint checkpoint, const ScopedLambda<void(VirtualRegister)>& functor)
 {
+
+    auto defAt = [&] (Checkpoint target, VirtualRegister operand) {
+        if (target == checkpoint)
+            functor(operand);
+    };
+
     switch (instruction->opcodeID()) {
     case op_wide16:
     case op_wide32:
@@ -412,10 +453,23 @@
     DEFS(OpNewAsyncGeneratorFuncExp, dst)
     DEFS(OpNewAsyncFunc, dst)
     DEFS(OpNewAsyncFuncExp, dst)
-    DEFS(OpCallVarargs, dst)
-    DEFS(OpTailCallVarargs, dst)
+    case op_call_varargs: {
+        auto bytecode = instruction->as<OpCallVarargs>();
+        defAt(OpCallVarargs::makeCall, bytecode.m_dst);
+        return;
+    }
+    case op_tail_call_varargs: {
+        auto bytecode = instruction->as<OpTailCallVarargs>();
+        defAt(OpTailCallVarargs::makeCall, bytecode.m_dst);
+        return;
+    }
+    case op_construct_varargs: {
+        auto bytecode = instruction->as<OpConstructVarargs>();
+        defAt(OpConstructVarargs::makeCall, bytecode.m_dst);
+        return;
+    }
+
     DEFS(OpTailCallForwardArguments, dst)
-    DEFS(OpConstructVarargs, dst)
     DEFS(OpGetFromScope, dst)
     DEFS(OpCall, dst)
     DEFS(OpTailCall, dst)
@@ -501,9 +555,25 @@
 
     DEFS(OpCatch, exception, thrownValue)
 
-    DEFS(OpIteratorOpen, iterator, next)
-    DEFS(OpIteratorNext, done, value)
+    case op_iterator_open: {
+        auto bytecode = instruction->as<OpIteratorOpen>();
 
+        defAt(OpIteratorOpen::symbolCall, bytecode.m_iterator);
+        defAt(OpIteratorOpen::getNext, bytecode.m_next);
+        return;
+    }
+
+    case op_iterator_next: {
+        auto bytecode = instruction->as<OpIteratorNext>();
+
+        defAt(OpIteratorNext::getDone, bytecode.m_done);
+        // We need to claim we set m_value here because we could early exit from the bytecode if we are done.
+        defAt(OpIteratorNext::getDone, bytecode.m_value);
+
+        defAt(OpIteratorNext::getValue, bytecode.m_value);
+        return;
+    }
+
     case op_enter: {
         for (unsigned i = numVars; i--;)
             functor(virtualRegisterForLocal(i));

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -32,23 +32,23 @@
 
 namespace JSC {
 
-void computeUsesForBytecodeIndexImpl(VirtualRegister, const Instruction*, const Function<void(VirtualRegister)>&);
-void computeDefsForBytecodeIndexImpl(unsigned, const Instruction*, const Function<void(VirtualRegister)>&);
+void computeUsesForBytecodeIndexImpl(VirtualRegister, const Instruction*, Checkpoint, const ScopedLambda<void(VirtualRegister)>&);
+void computeDefsForBytecodeIndexImpl(unsigned, const Instruction*, Checkpoint, const ScopedLambda<void(VirtualRegister)>&);
 
-template<typename Block>
-void computeUsesForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+template<typename Block, typename Functor>
+void computeUsesForBytecodeIndex(Block* codeBlock, const Instruction* instruction, Checkpoint checkpoint, const Functor& functor)
 {
     OpcodeID opcodeID = instruction->opcodeID();
     if (opcodeID != op_enter && (codeBlock->wasCompiledWithDebuggingOpcodes() || codeBlock->usesEval()) && codeBlock->scopeRegister().isValid())
         functor(codeBlock->scopeRegister());
 
-    computeUsesForBytecodeIndexImpl(codeBlock->scopeRegister(), instruction, functor);
+    computeUsesForBytecodeIndexImpl(codeBlock->scopeRegister(), instruction, checkpoint, scopedLambda<void(VirtualRegister)>(functor));
 }
 
-template<typename Block>
-void computeDefsForBytecodeIndex(Block* codeBlock, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
+template<typename Block, typename Functor>
+void computeDefsForBytecodeIndex(Block* codeBlock, const Instruction* instruction, Checkpoint checkpoint, const Functor& functor)
 {
-    computeDefsForBytecodeIndexImpl(codeBlock->numVars(), instruction, functor);
+    computeDefsForBytecodeIndexImpl(codeBlock->numVars(), instruction, checkpoint, scopedLambda<void(VirtualRegister)>(functor));
 }
 
 #undef CALL_FUNCTOR

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -34,7 +34,7 @@
 #include "BasicBlockLocation.h"
 #include "ByValInfo.h"
 #include "BytecodeDumper.h"
-#include "BytecodeLivenessAnalysis.h"
+#include "BytecodeLivenessAnalysisInlines.h"
 #include "BytecodeOperandsForCheckpoint.h"
 #include "BytecodeStructs.h"
 #include "CodeBlockInlines.h"
@@ -1924,7 +1924,7 @@
     // into the DFG.
 
     auto nextOffset = instructions().at(bytecodeIndex).next().offset();
-    FastBitVector liveLocals = bytecodeLiveness.getLivenessInfoAtBytecodeIndex(this, BytecodeIndex(nextOffset));
+    FastBitVector liveLocals = bytecodeLiveness.getLivenessInfoAtInstruction(this, BytecodeIndex(nextOffset));
     Vector<VirtualRegister> liveOperands;
     liveOperands.reserveInitialCapacity(liveLocals.bitCount());
     liveLocals.forEachSetBit([&] (unsigned liveLocal) {
@@ -3110,7 +3110,7 @@
 {
     BytecodeLivenessAnalysis liveness(this); // Compute directly from scratch so it doesn't effect CodeBlock footprint.
     
-    FastBitVector liveAtHead = liveness.getLivenessInfoAtBytecodeIndex(this, BytecodeIndex(0));
+    FastBitVector liveAtHead = liveness.getLivenessInfoAtInstruction(this, BytecodeIndex(0));
     
     if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeLocals)) {
         beginValidationDidFail();

Modified: trunk/Source/_javascript_Core/bytecode/FullBytecodeLiveness.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/FullBytecodeLiveness.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/FullBytecodeLiveness.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -35,18 +35,19 @@
 class CodeBlock;
 
 // Note: Full bytecode liveness does not track any information about the liveness of temps.
-// If you want tmp liveness for a checkpoint ask livenessForCheckpoint.
+// If you want tmp liveness for a checkpoint ask tmpLivenessForCheckpoint.
 class FullBytecodeLiveness {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     const FastBitVector& getLiveness(BytecodeIndex bytecodeIndex, LivenessCalculationPoint point) const
     {
-        // FIXME: What should this do when we have checkpoints?
+        // We don't have to worry about overflowing into the next bytecodeoffset in our vectors because we
+        // static assert that bytecode length is greater than the number of checkpoints in BytecodeStructs.h
         switch (point) {
         case LivenessCalculationPoint::BeforeUse:
-            return m_beforeUseVector[bytecodeIndex.offset()];
+            return m_usesBefore[toIndex(bytecodeIndex)];
         case LivenessCalculationPoint::AfterUse:
-            return m_afterUseVector[bytecodeIndex.offset()];
+            return m_usesAfter[toIndex(bytecodeIndex)];
         }
         RELEASE_ASSERT_NOT_REACHED();
     }
@@ -59,10 +60,12 @@
 private:
     friend class BytecodeLivenessAnalysis;
     
+    static size_t toIndex(BytecodeIndex bytecodeIndex) { return bytecodeIndex.offset() + bytecodeIndex.checkpoint(); }
+
     // FIXME: Use FastBitVector's view mechanism to make them compact.
-    // https://bugs.webkit.org/show_bug.cgi?id=204427<Paste>
-    Vector<FastBitVector, 0, UnsafeVectorOverflow> m_beforeUseVector;
-    Vector<FastBitVector, 0, UnsafeVectorOverflow> m_afterUseVector;
+    // https://bugs.webkit.org/show_bug.cgi?id=204427
+    Vector<FastBitVector, 0, UnsafeVectorOverflow> m_usesBefore;
+    Vector<FastBitVector, 0, UnsafeVectorOverflow> m_usesAfter;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/bytecode/Instruction.h (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecode/Instruction.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecode/Instruction.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -39,6 +39,7 @@
     static constexpr OpcodeID wide32 = op_wide32;
     static constexpr const unsigned* opcodeLengths = ::JSC::opcodeLengths;
     static constexpr const char* const* opcodeNames = ::JSC::opcodeNames;
+    static constexpr auto checkpointCountTable = bytecodeCheckpointCountTable;
 };
 
 struct WasmOpcodeTraits {
@@ -50,6 +51,7 @@
     static constexpr OpcodeID wide32 = wasm_wide32;
     static constexpr const unsigned* opcodeLengths = wasmOpcodeLengths;
     static constexpr const char* const* opcodeNames = wasmOpcodeNames;
+    static constexpr auto checkpointCountTable = wasmCheckpointCountTable;
 };
 
 
@@ -123,6 +125,14 @@
     }
 
     template<typename Traits = JSOpcodeTraits>
+    unsigned numberOfCheckpoints() const
+    {
+        if (!hasCheckpoints<Traits>())
+            return 1;
+        return Traits::checkpointCountTable[opcodeID<Traits>()];
+    }
+
+    template<typename Traits = JSOpcodeTraits>
     int sizeShiftAmount() const
     {
         if (isWide32<Traits>())

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -5215,10 +5215,12 @@
     for (unsigned offset = bodyBytecodeStartOffset(); isValid() && offset < bodyBytecodeEndOffset;) {
         auto instruction = generator.instructions().at(offset);
         ASSERT(!instruction->is<OpEnter>());
-        computeDefsForBytecodeIndex(codeBlock, instruction.ptr(), [&] (VirtualRegister operand) {
-            if (local()->virtualRegister() == operand)
-                invalidate();
-        });
+        for (Checkpoint checkpoint = instruction->numberOfCheckpoints(); checkpoint--;) {
+            computeDefsForBytecodeIndex(codeBlock, instruction.ptr(), checkpoint, [&] (VirtualRegister operand) {
+                if (local()->virtualRegister() == operand)
+                    invalidate();
+            });
+        }
         offset += instruction->size();
     }
 }

Modified: trunk/Source/_javascript_Core/dfg/DFGForAllKills.h (264048 => 264049)


--- trunk/Source/_javascript_Core/dfg/DFGForAllKills.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/dfg/DFGForAllKills.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -79,18 +79,21 @@
             ASSERT(before.bytecodeIndex().checkpoint() != after.bytecodeIndex().checkpoint());
             ASSERT_WITH_MESSAGE(before.bytecodeIndex().offset() == after.bytecodeIndex().offset() || nodeAfter->op() == ExitOK || nodeAfter->op() == InvalidationPoint, "When the DFG does code motion it should change the forExit origin to match the surrounding bytecodes.");
 
-            auto checkpointLiveBefore = livenessForCheckpoint(*codeBlock, before.bytecodeIndex());
-            auto checkpointLiveAfter = livenessForCheckpoint(*codeBlock, after.bytecodeIndex());
+            auto liveBefore = tmpLivenessForCheckpoint(*codeBlock, before.bytecodeIndex());
+            auto liveAfter = tmpLivenessForCheckpoint(*codeBlock, after.bytecodeIndex());
+            liveAfter.invert();
+            liveBefore.filter(liveAfter);
 
-            FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock);
-            const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex(), LivenessCalculationPoint::BeforeUse);
+            liveBefore.forEachSetBit([&] (size_t tmp) {
+                functor(remapOperand(beforeInlineCallFrame, Operand::tmp(tmp)));
+            });
+        } else if (before.bytecodeIndex().checkpoint()) {
+            // We are moving on to another bytecode, all temps should be dead now.
+            auto liveBefore = tmpLivenessForCheckpoint(*codeBlock, before.bytecodeIndex());
 
-            for (Operand operand : checkpointLiveBefore) {
-                if (checkpointLiveAfter.contains(operand) || (!operand.isTmp() && liveAfter[operand.virtualRegister().offset()]))
-                    continue;
-                functor(remapOperand(beforeInlineCallFrame, operand));
-            }
-            return;
+            liveBefore.forEachSetBit([&] (size_t tmp) {
+                functor(remapOperand(beforeInlineCallFrame, Operand::tmp(tmp)));
+            });
         }
 
         FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock);

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -1152,8 +1152,8 @@
             if (!codeBlock->numTmps() || operandIndex < tmpOffset)
                 continue;
 
-            auto live = livenessForCheckpoint(*codeBlock, codeOriginPtr->bytecodeIndex());
-            return live.contains(operand);
+            auto bitMap = tmpLivenessForCheckpoint(*codeBlock, codeOriginPtr->bytecodeIndex());
+            return bitMap.get(operandIndex - tmpOffset);
         }
 
         VirtualRegister reg = operand.virtualRegister() - codeOriginPtr->stackOffset();

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (264048 => 264049)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2020-07-08 00:32:35 UTC (rev 264049)
@@ -904,9 +904,10 @@
 
             if (codeOriginPtr->bytecodeIndex().checkpoint()) {
                 ASSERT(codeBlock->numTmps());
-                auto live = livenessForCheckpoint(*codeBlock, codeOriginPtr->bytecodeIndex());
-                for (Operand operand : live)
-                    functor(remapOperand(inlineCallFrame, operand));
+                auto liveTmps = tmpLivenessForCheckpoint(*codeBlock, codeOriginPtr->bytecodeIndex());
+                liveTmps.forEachSetBit([&] (size_t tmp) {
+                    functor(remapOperand(inlineCallFrame, Operand::tmp(tmp)));
+                });
             }
             
             if (!inlineCallFrame)

Modified: trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -88,7 +88,7 @@
             });
         
         if (DFGMovHintRemovalPhaseInternal::verbose)
-            dataLog("    Locals: ", m_state, "\n");
+            dataLog("    Locals at ", block->terminal()->origin.forExit, ": ", m_state, "\n");
         
         // Assume that blocks after us exit.
         currentEpoch.bump();
@@ -99,7 +99,7 @@
             if (node->op() == MovHint) {
                 Epoch localEpoch = m_state.operand(node->unlinkedOperand());
                 if (DFGMovHintRemovalPhaseInternal::verbose)
-                    dataLog("    At ", node, ": current = ", currentEpoch, ", local = ", localEpoch, "\n");
+                    dataLog("    At ", node, " (", node->unlinkedOperand(), "): current = ", currentEpoch, ", local = ", localEpoch, "\n");
                 if (!localEpoch || localEpoch == currentEpoch) {
                     node->setOpAndDefaultFlags(ZombieHint);
                     node->child1() = Edge();

Modified: trunk/Source/_javascript_Core/dfg/DFGPlan.cpp (264048 => 264049)


--- trunk/Source/_javascript_Core/dfg/DFGPlan.cpp	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/dfg/DFGPlan.cpp	2020-07-08 00:32:35 UTC (rev 264049)
@@ -758,7 +758,7 @@
         return;
 
     CodeBlock* alternative = m_codeBlock->alternative();
-    FastBitVector liveness = alternative->livenessAnalysis().getLivenessInfoAtBytecodeIndex(alternative, m_osrEntryBytecodeIndex);
+    FastBitVector liveness = alternative->livenessAnalysis().getLivenessInfoAtInstruction(alternative, m_osrEntryBytecodeIndex);
 
     for (unsigned local = m_mustHandleValues.numberOfLocals(); local--;) {
         if (!liveness[local])

Modified: trunk/Source/_javascript_Core/generator/Opcode.rb (264048 => 264049)


--- trunk/Source/_javascript_Core/generator/Opcode.rb	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/generator/Opcode.rb	2020-07-08 00:32:35 UTC (rev 264049)
@@ -130,9 +130,11 @@
         <<-EOF
 struct #{capitalized_name} : public Instruction {
     #{opcodeID}
+    #{lengthValue}
     #{temps}
     #{checkpointValues}
 
+
 #{emitter}
 #{dumper}
 #{constructors}
@@ -139,6 +141,7 @@
 #{setters}#{metadata_struct_and_accessor}
 #{members}
 };
+#{checkpointSizeAssert}
 EOF
     end
 
@@ -146,6 +149,10 @@
         "static constexpr #{opcodeIDType} opcodeID = #{name};"
     end
 
+    def lengthValue
+        "static constexpr size_t length = #{length};"
+    end
+
     def checkpointValues
         return if @checkpoints.nil?
 
@@ -152,6 +159,12 @@
         ["enum Checkpoints : uint8_t {"].concat(checkpoints.map{ |checkpoint| "        #{checkpoint}," }).concat(["        numberOfCheckpoints,", "    };"]).join("\n")
     end
 
+    def checkpointSizeAssert
+        return if @checkpoints.nil?
+
+        "static_assert(#{capitalized_name}::length > #{capitalized_name}::numberOfCheckpoints, \"FullBytecodeLivess relies on the length of #{capitalized_name} being greater than the number of checkpoints\");"
+    end
+
     def temps
         return if @tmps.nil?
 

Modified: trunk/Source/_javascript_Core/generator/Section.rb (264048 => 264049)


--- trunk/Source/_javascript_Core/generator/Section.rb	2020-07-07 23:38:59 UTC (rev 264048)
+++ trunk/Source/_javascript_Core/generator/Section.rb	2020-07-08 00:32:35 UTC (rev 264049)
@@ -84,13 +84,16 @@
 
       if config[:emit_in_structs_file]
           i = 0
+          out.write("static constexpr unsigned #{config[:macro_name_component].downcase}CheckpointCountTable[] = {\n")
           while true
               if !opcodes[i].checkpoints
-                  out << "\n"
+                  out << "    0, // this unused entry is needed since MSVC won't compile empty arrays\n"
+                  out << "};\n\n"
                   out << "#define NUMBER_OF_#{config[:macro_name_component]}_WITH_CHECKPOINTS #{i}\n"
                   break
               end
 
+              out.write("    #{opcodes[i].checkpoints.length},\n")
               i += 1
           end
           out << "\n"
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to