Change bytecode dumping to dump the bytecode control flow graph
https://bugs.webkit.org/show_bug.cgi?id=213669

Reviewed by Yusuke Suzuki.

This makes the bytecode control flow graphs much easier to understand, and
puts bytecode dumping in more in line with how we dump other IRs.

The new dumps look like this:
```
foo#Ahf63N:[0x1035bc120->0x1035e5100, NoneFunctionCall, 36]: 13 instructions (0 16-bit instructions, 0 32-bit instructions, 1 instructions with metadata); 156 bytes (120 metadata bytes); 2 parameter(s); 8 callee register(s); 6 variable(s); scope at loc4

bb#1
[   0] enter
[   1] get_scope          loc4
[   3] mov                loc5, loc4
[   6] check_traps
[   7] mov                loc6, <JSValue()>(const0)
[  10] mov                loc6, Undefined(const1)
[  13] mod                loc7, arg1, Int32: 2(const2)
[  17] jfalse             loc7, 8(->25)
Successors: [ #3 #2 ]

bb#2
[  20] mov                loc6, Int32: 42(const3)
[  23] jmp                5(->28)
Successors: [ #4 ]

bb#3
[  25] mov                loc6, Int32: 77(const4)
Successors: [ #4 ]

bb#4
[  28] add                loc7, arg1, loc6, OperandTypes(126, 126)
[  34] ret                loc7
Successors: [ ]
```

* bytecode/BytecodeDumper.cpp:
(JSC::dumpHeader):
(JSC::dumpFooter):
(JSC::CodeBlockBytecodeDumper<Block>::dumpBlock):
(JSC::CodeBlockBytecodeDumper<Block>::dumpGraph):
* bytecode/BytecodeDumper.h:
* bytecode/BytecodeGraph.h:
(JSC::BytecodeGraph::dump):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263618 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index e245c8d..dd47251 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,54 @@
+2020-06-27  Saam Barati  <sbarati@apple.com>
+
+        Change bytecode dumping to dump the bytecode control flow graph
+        https://bugs.webkit.org/show_bug.cgi?id=213669
+
+        Reviewed by Yusuke Suzuki.
+
+        This makes the bytecode control flow graphs much easier to understand, and
+        puts bytecode dumping in more in line with how we dump other IRs.
+        
+        The new dumps look like this:
+        ```
+        foo#Ahf63N:[0x1035bc120->0x1035e5100, NoneFunctionCall, 36]: 13 instructions (0 16-bit instructions, 0 32-bit instructions, 1 instructions with metadata); 156 bytes (120 metadata bytes); 2 parameter(s); 8 callee register(s); 6 variable(s); scope at loc4
+        
+        bb#1
+        [   0] enter              
+        [   1] get_scope          loc4
+        [   3] mov                loc5, loc4
+        [   6] check_traps        
+        [   7] mov                loc6, <JSValue()>(const0)
+        [  10] mov                loc6, Undefined(const1)
+        [  13] mod                loc7, arg1, Int32: 2(const2)
+        [  17] jfalse             loc7, 8(->25)
+        Successors: [ #3 #2 ]
+        
+        bb#2
+        [  20] mov                loc6, Int32: 42(const3)
+        [  23] jmp                5(->28)
+        Successors: [ #4 ]
+        
+        bb#3
+        [  25] mov                loc6, Int32: 77(const4)
+        Successors: [ #4 ]
+        
+        bb#4
+        [  28] add                loc7, arg1, loc6, OperandTypes(126, 126)
+        [  34] ret                loc7
+        Successors: [ ]
+        ```
+
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::dumpHeader):
+        (JSC::dumpFooter):
+        (JSC::CodeBlockBytecodeDumper<Block>::dumpBlock):
+        (JSC::CodeBlockBytecodeDumper<Block>::dumpGraph):
+        * bytecode/BytecodeDumper.h:
+        * bytecode/BytecodeGraph.h:
+        (JSC::BytecodeGraph::dump):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+
 2020-06-27  Stephan Szabo  <stephan.szabo@sony.com>
 
         [PlayStation] Update test runner for changes to Options and signing
diff --git a/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp b/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
index c240d9f..97450c3 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
+++ b/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
@@ -28,6 +28,7 @@
 #include "BytecodeDumper.h"
 
 #include "BytecodeGenerator.h"
+#include "BytecodeGraph.h"
 #include "BytecodeStructs.h"
 #include "CodeBlock.h"
 #include "JSCJSValueInlines.h"
@@ -211,8 +212,8 @@
     }
 }
 
-template<class Block>
-void CodeBlockBytecodeDumper<Block>::dumpBlock(Block* block, const InstructionStream& instructions, PrintStream& out, const ICStatusMap& statusMap)
+template <typename Block>
+static void dumpHeader(Block* block, const InstructionStream& instructions, PrintStream& out)
 {
     size_t instructionCount = 0;
     size_t wide16InstructionCount = 0;
@@ -241,16 +242,62 @@
         block->numParameters(), block->numCalleeLocals(), block->numVars());
     out.print("; scope at ", block->scopeRegister());
     out.printf("\n");
+}
 
-    CodeBlockBytecodeDumper<Block> dumper(block, out);
-    for (const auto& it : instructions)
-        dumper.dumpBytecode(it, statusMap);
-
+template <typename Dumper>
+static void dumpFooter(Dumper& dumper)
+{
     dumper.dumpIdentifiers();
     dumper.dumpConstants();
     dumper.dumpExceptionHandlers();
     dumper.dumpSwitchJumpTables();
     dumper.dumpStringSwitchJumpTables();
+}
+
+template<class Block>
+void CodeBlockBytecodeDumper<Block>::dumpBlock(Block* block, const InstructionStream& instructions, PrintStream& out, const ICStatusMap& statusMap)
+{
+    dumpHeader(block, instructions, out);
+
+    CodeBlockBytecodeDumper<Block> dumper(block, out);
+    for (const auto& it : instructions)
+        dumper.dumpBytecode(it, statusMap);
+
+    dumpFooter(dumper);
+
+    out.printf("\n");
+}
+
+template<class Block>
+void CodeBlockBytecodeDumper<Block>::dumpGraph(Block* block, const InstructionStream& instructions, BytecodeGraph& graph, PrintStream& out, const ICStatusMap& icStatusMap)
+{
+    dumpHeader(block, instructions, out);
+
+    CodeBlockBytecodeDumper<Block> dumper(block, out);
+
+    out.printf("\n");
+
+    for (BytecodeBasicBlock& block : graph) {
+        if (block.isEntryBlock() || block.isExitBlock())
+            continue;
+
+        out.print("bb#", block.index(), "\n");
+
+        for (unsigned i = 0; i < block.totalLength(); ) {
+            auto& currentInstruction = instructions.at(i + block.leaderOffset());
+            dumper.dumpBytecode(currentInstruction, icStatusMap);
+            i += currentInstruction.ptr()->size();
+        }
+
+        out.print("Successors: [");
+        for (unsigned successor : block.successors()) {
+            if (!graph[successor].isExitBlock())
+                out.print(" #", successor);
+        }
+        out.print(" ]\n\n");
+    }
+
+    dumpFooter(dumper);
 
     out.printf("\n");
 }
diff --git a/Source/JavaScriptCore/bytecode/BytecodeDumper.h b/Source/JavaScriptCore/bytecode/BytecodeDumper.h
index ec6457b..1e5d269 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeDumper.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeDumper.h
@@ -34,6 +34,8 @@
 
 namespace JSC {
 
+class BytecodeGraph;
+
 struct Instruction;
 
 class BytecodeDumperBase {
@@ -104,6 +106,13 @@
 class CodeBlockBytecodeDumper final : public BytecodeDumper<Block> {
 public:
     static void dumpBlock(Block*, const InstructionStream&, PrintStream& out, const ICStatusMap& = ICStatusMap());
+    static void dumpGraph(Block*, const InstructionStream&, BytecodeGraph&, PrintStream& out = WTF::dataFile(), const ICStatusMap& = ICStatusMap());
+
+    void dumpIdentifiers();
+    void dumpConstants();
+    void dumpExceptionHandlers();
+    void dumpSwitchJumpTables();
+    void dumpStringSwitchJumpTables();
 
 private:
     using BytecodeDumper<Block>::BytecodeDumper;
@@ -111,12 +120,6 @@
     ALWAYS_INLINE VM& vm() const;
 
     const Identifier& identifier(int index) const;
-
-    void dumpIdentifiers();
-    void dumpConstants();
-    void dumpExceptionHandlers();
-    void dumpSwitchJumpTables();
-    void dumpStringSwitchJumpTables();
 };
 
 #if ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/bytecode/BytecodeGraph.h b/Source/JavaScriptCore/bytecode/BytecodeGraph.h
index db2c65a..0f595d4 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeGraph.h
+++ b/Source/JavaScriptCore/bytecode/BytecodeGraph.h
@@ -27,6 +27,7 @@
 #pragma once
 
 #include "BytecodeBasicBlock.h"
+#include "BytecodeDumper.h"
 #include <wtf/IndexedContainerIterator.h>
 #include <wtf/IteratorRange.h>
 #include <wtf/Vector.h>
@@ -99,6 +100,13 @@
     BytecodeBasicBlock& first() { return at(0); }
     BytecodeBasicBlock& last() { return at(size() - 1); }
 
+
+    template <typename CodeBlockType>
+    void dump(CodeBlockType* codeBlock, const InstructionStream& instructions, Optional<Vector<Operands<SpeculatedType>>> speculationAtHead, PrintStream& printer = WTF::dataFile())
+    {
+        CodeBlockBytecodeDumper<CodeBlockType>::dumpGraph(codeBlock, instructions, *this, speculationAtHead, printer);
+    }
+
 private:
     BasicBlocksVector m_basicBlocks;
 };
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 91805c4..36e8d81 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -231,7 +231,8 @@
 {
     ICStatusMap statusMap;
     getICStatusMap(statusMap);
-    CodeBlockBytecodeDumper<CodeBlock>::dumpBlock(this, instructions(), out, statusMap);
+    BytecodeGraph graph(this, this->instructions());
+    CodeBlockBytecodeDumper<CodeBlock>::dumpGraph(this, instructions(), graph, out, statusMap);
 }
 
 void CodeBlock::dumpBytecode(PrintStream& out, const InstructionStream::Ref& it, const ICStatusMap& statusMap)