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"