[JSC] Allow UnlinkedCodeBlock to dump its bytecode sequence
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Mar 2017 08:15:45 +0000 (08:15 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Mar 2017 08:15:45 +0000 (08:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=168968

Reviewed by Saam Barati.

This patch decouples dumping bytecode sequence from CodeBlock.
This change allows UnlinkedCodeBlock to dump its bytecode sequence.
It is useful because we now have complex phase between UnlinkedCodeBlock and CodeBlock,
called Generatorification.

We introduce BytecodeDumper<Block>. Both CodeBlock and UnlinkedCodeBlock can use
this class to dump bytecode sequence.

And this patch also adds Option::dumpBytecodesBeforeGeneratorification,
which dumps unlinked bytecode sequence before generatorification if it is enabled.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeDumper.cpp: Added.
(JSC::getStructureID):
(JSC::getSpecialPointer):
(JSC::getPutByIdFlags):
(JSC::getToThisStatus):
(JSC::getPointer):
(JSC::getStructureChain):
(JSC::getStructure):
(JSC::getCallLinkInfo):
(JSC::getBasicBlockLocation):
(JSC::BytecodeDumper<Block>::actualPointerFor):
(JSC::BytecodeDumper<CodeBlock>::actualPointerFor):
(JSC::beginDumpProfiling):
(JSC::BytecodeDumper<Block>::dumpValueProfiling):
(JSC::BytecodeDumper<CodeBlock>::dumpValueProfiling):
(JSC::BytecodeDumper<Block>::dumpArrayProfiling):
(JSC::BytecodeDumper<CodeBlock>::dumpArrayProfiling):
(JSC::BytecodeDumper<Block>::dumpProfilesForBytecodeOffset):
(JSC::dumpRareCaseProfile):
(JSC::dumpArithProfile):
(JSC::BytecodeDumper<CodeBlock>::dumpProfilesForBytecodeOffset):
(JSC::BytecodeDumper<Block>::vm):
(JSC::BytecodeDumper<Block>::identifier):
(JSC::regexpToSourceString):
(JSC::regexpName):
(JSC::printLocationAndOp):
(JSC::isConstantRegisterIndex):
(JSC::debugHookName):
(JSC::BytecodeDumper<Block>::registerName):
(JSC::idName):
(JSC::BytecodeDumper<Block>::constantName):
(JSC::BytecodeDumper<Block>::printUnaryOp):
(JSC::BytecodeDumper<Block>::printBinaryOp):
(JSC::BytecodeDumper<Block>::printConditionalJump):
(JSC::BytecodeDumper<Block>::printGetByIdOp):
(JSC::dumpStructure):
(JSC::dumpChain):
(JSC::BytecodeDumper<Block>::printGetByIdCacheStatus):
(JSC::BytecodeDumper<Block>::printPutByIdCacheStatus):
(JSC::BytecodeDumper<Block>::dumpCallLinkStatus):
(JSC::BytecodeDumper<CodeBlock>::dumpCallLinkStatus):
(JSC::BytecodeDumper<Block>::printCallOp):
(JSC::BytecodeDumper<Block>::printPutByIdOp):
(JSC::BytecodeDumper<Block>::printLocationOpAndRegisterOperand):
(JSC::BytecodeDumper<Block>::dumpBytecode):
(JSC::BytecodeDumper<Block>::dumpIdentifiers):
(JSC::BytecodeDumper<Block>::dumpConstants):
(JSC::BytecodeDumper<Block>::dumpRegExps):
(JSC::BytecodeDumper<Block>::dumpExceptionHandlers):
(JSC::BytecodeDumper<Block>::dumpSwitchJumpTables):
(JSC::BytecodeDumper<Block>::dumpStringSwitchJumpTables):
(JSC::BytecodeDumper<Block>::dumpBlock):
* bytecode/BytecodeDumper.h: Added.
(JSC::BytecodeDumper::BytecodeDumper):
(JSC::BytecodeDumper::block):
(JSC::BytecodeDumper::instructionsBegin):
* bytecode/BytecodeGeneratorification.cpp:
(JSC::BytecodeGeneratorification::BytecodeGeneratorification):
(JSC::performGeneratorification):
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::BytecodeLivenessAnalysis::dumpResults):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::propagateTransitions):
(JSC::CodeBlock::finalizeLLIntInlineCaches):
(JSC::CodeBlock::hasOpDebugForLineAndColumn):
(JSC::CodeBlock::usesOpcode):
(JSC::CodeBlock::valueProfileForBytecodeOffset):
(JSC::CodeBlock::arithProfileForPC):
(JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler):
(JSC::idName): Deleted.
(JSC::CodeBlock::registerName): Deleted.
(JSC::CodeBlock::constantName): Deleted.
(JSC::regexpToSourceString): Deleted.
(JSC::regexpName): Deleted.
(JSC::debugHookName): Deleted.
(JSC::CodeBlock::printUnaryOp): Deleted.
(JSC::CodeBlock::printBinaryOp): Deleted.
(JSC::CodeBlock::printConditionalJump): Deleted.
(JSC::CodeBlock::printGetByIdOp): Deleted.
(JSC::dumpStructure): Deleted.
(JSC::dumpChain): Deleted.
(JSC::CodeBlock::printGetByIdCacheStatus): Deleted.
(JSC::CodeBlock::printPutByIdCacheStatus): Deleted.
(JSC::CodeBlock::printCallOp): Deleted.
(JSC::CodeBlock::printPutByIdOp): Deleted.
(JSC::CodeBlock::dumpExceptionHandlers): Deleted.
(JSC::CodeBlock::beginDumpProfiling): Deleted.
(JSC::CodeBlock::dumpValueProfiling): Deleted.
(JSC::CodeBlock::dumpArrayProfiling): Deleted.
(JSC::CodeBlock::dumpRareCaseProfile): Deleted.
(JSC::CodeBlock::dumpArithProfile): Deleted.
(JSC::CodeBlock::printLocationAndOp): Deleted.
(JSC::CodeBlock::printLocationOpAndRegisterOperand): Deleted.
* bytecode/CodeBlock.h:
(JSC::CodeBlock::constantRegisters):
(JSC::CodeBlock::numberOfRegExps):
(JSC::CodeBlock::bitVectors):
(JSC::CodeBlock::bitVector):
* bytecode/HandlerInfo.h:
(JSC::HandlerInfoBase::typeName):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::dump):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::getConstant):
* bytecode/UnlinkedInstructionStream.cpp:
(JSC::UnlinkedInstructionStream::UnlinkedInstructionStream):
* bytecode/UnlinkedInstructionStream.h:
(JSC::UnlinkedInstructionStream::Reader::next):
* runtime/Options.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@213209 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeDumper.cpp [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeDumper.h [new file with mode: 0644]
Source/JavaScriptCore/bytecode/BytecodeGeneratorification.cpp
Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/HandlerInfo.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedInstructionStream.cpp
Source/JavaScriptCore/bytecode/UnlinkedInstructionStream.h
Source/JavaScriptCore/runtime/Options.h

index c05bee7..9598c3e 100644 (file)
@@ -194,6 +194,7 @@ set(JavaScriptCore_SOURCES
     bytecode/ArrayAllocationProfile.cpp
     bytecode/ArrayProfile.cpp
     bytecode/BytecodeBasicBlock.cpp
+    bytecode/BytecodeDumper.cpp
     bytecode/BytecodeGeneratorification.cpp
     bytecode/BytecodeIntrinsicRegistry.cpp
     bytecode/BytecodeLivenessAnalysis.cpp
index 2a1e268..090d07a 100644 (file)
@@ -1,3 +1,135 @@
+2017-03-01  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Allow UnlinkedCodeBlock to dump its bytecode sequence
+        https://bugs.webkit.org/show_bug.cgi?id=168968
+
+        Reviewed by Saam Barati.
+
+        This patch decouples dumping bytecode sequence from CodeBlock.
+        This change allows UnlinkedCodeBlock to dump its bytecode sequence.
+        It is useful because we now have complex phase between UnlinkedCodeBlock and CodeBlock,
+        called Generatorification.
+
+        We introduce BytecodeDumper<Block>. Both CodeBlock and UnlinkedCodeBlock can use
+        this class to dump bytecode sequence.
+
+        And this patch also adds Option::dumpBytecodesBeforeGeneratorification,
+        which dumps unlinked bytecode sequence before generatorification if it is enabled.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeDumper.cpp: Added.
+        (JSC::getStructureID):
+        (JSC::getSpecialPointer):
+        (JSC::getPutByIdFlags):
+        (JSC::getToThisStatus):
+        (JSC::getPointer):
+        (JSC::getStructureChain):
+        (JSC::getStructure):
+        (JSC::getCallLinkInfo):
+        (JSC::getBasicBlockLocation):
+        (JSC::BytecodeDumper<Block>::actualPointerFor):
+        (JSC::BytecodeDumper<CodeBlock>::actualPointerFor):
+        (JSC::beginDumpProfiling):
+        (JSC::BytecodeDumper<Block>::dumpValueProfiling):
+        (JSC::BytecodeDumper<CodeBlock>::dumpValueProfiling):
+        (JSC::BytecodeDumper<Block>::dumpArrayProfiling):
+        (JSC::BytecodeDumper<CodeBlock>::dumpArrayProfiling):
+        (JSC::BytecodeDumper<Block>::dumpProfilesForBytecodeOffset):
+        (JSC::dumpRareCaseProfile):
+        (JSC::dumpArithProfile):
+        (JSC::BytecodeDumper<CodeBlock>::dumpProfilesForBytecodeOffset):
+        (JSC::BytecodeDumper<Block>::vm):
+        (JSC::BytecodeDumper<Block>::identifier):
+        (JSC::regexpToSourceString):
+        (JSC::regexpName):
+        (JSC::printLocationAndOp):
+        (JSC::isConstantRegisterIndex):
+        (JSC::debugHookName):
+        (JSC::BytecodeDumper<Block>::registerName):
+        (JSC::idName):
+        (JSC::BytecodeDumper<Block>::constantName):
+        (JSC::BytecodeDumper<Block>::printUnaryOp):
+        (JSC::BytecodeDumper<Block>::printBinaryOp):
+        (JSC::BytecodeDumper<Block>::printConditionalJump):
+        (JSC::BytecodeDumper<Block>::printGetByIdOp):
+        (JSC::dumpStructure):
+        (JSC::dumpChain):
+        (JSC::BytecodeDumper<Block>::printGetByIdCacheStatus):
+        (JSC::BytecodeDumper<Block>::printPutByIdCacheStatus):
+        (JSC::BytecodeDumper<Block>::dumpCallLinkStatus):
+        (JSC::BytecodeDumper<CodeBlock>::dumpCallLinkStatus):
+        (JSC::BytecodeDumper<Block>::printCallOp):
+        (JSC::BytecodeDumper<Block>::printPutByIdOp):
+        (JSC::BytecodeDumper<Block>::printLocationOpAndRegisterOperand):
+        (JSC::BytecodeDumper<Block>::dumpBytecode):
+        (JSC::BytecodeDumper<Block>::dumpIdentifiers):
+        (JSC::BytecodeDumper<Block>::dumpConstants):
+        (JSC::BytecodeDumper<Block>::dumpRegExps):
+        (JSC::BytecodeDumper<Block>::dumpExceptionHandlers):
+        (JSC::BytecodeDumper<Block>::dumpSwitchJumpTables):
+        (JSC::BytecodeDumper<Block>::dumpStringSwitchJumpTables):
+        (JSC::BytecodeDumper<Block>::dumpBlock):
+        * bytecode/BytecodeDumper.h: Added.
+        (JSC::BytecodeDumper::BytecodeDumper):
+        (JSC::BytecodeDumper::block):
+        (JSC::BytecodeDumper::instructionsBegin):
+        * bytecode/BytecodeGeneratorification.cpp:
+        (JSC::BytecodeGeneratorification::BytecodeGeneratorification):
+        (JSC::performGeneratorification):
+        * bytecode/BytecodeLivenessAnalysis.cpp:
+        (JSC::BytecodeLivenessAnalysis::dumpResults):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::propagateTransitions):
+        (JSC::CodeBlock::finalizeLLIntInlineCaches):
+        (JSC::CodeBlock::hasOpDebugForLineAndColumn):
+        (JSC::CodeBlock::usesOpcode):
+        (JSC::CodeBlock::valueProfileForBytecodeOffset):
+        (JSC::CodeBlock::arithProfileForPC):
+        (JSC::CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler):
+        (JSC::idName): Deleted.
+        (JSC::CodeBlock::registerName): Deleted.
+        (JSC::CodeBlock::constantName): Deleted.
+        (JSC::regexpToSourceString): Deleted.
+        (JSC::regexpName): Deleted.
+        (JSC::debugHookName): Deleted.
+        (JSC::CodeBlock::printUnaryOp): Deleted.
+        (JSC::CodeBlock::printBinaryOp): Deleted.
+        (JSC::CodeBlock::printConditionalJump): Deleted.
+        (JSC::CodeBlock::printGetByIdOp): Deleted.
+        (JSC::dumpStructure): Deleted.
+        (JSC::dumpChain): Deleted.
+        (JSC::CodeBlock::printGetByIdCacheStatus): Deleted.
+        (JSC::CodeBlock::printPutByIdCacheStatus): Deleted.
+        (JSC::CodeBlock::printCallOp): Deleted.
+        (JSC::CodeBlock::printPutByIdOp): Deleted.
+        (JSC::CodeBlock::dumpExceptionHandlers): Deleted.
+        (JSC::CodeBlock::beginDumpProfiling): Deleted.
+        (JSC::CodeBlock::dumpValueProfiling): Deleted.
+        (JSC::CodeBlock::dumpArrayProfiling): Deleted.
+        (JSC::CodeBlock::dumpRareCaseProfile): Deleted.
+        (JSC::CodeBlock::dumpArithProfile): Deleted.
+        (JSC::CodeBlock::printLocationAndOp): Deleted.
+        (JSC::CodeBlock::printLocationOpAndRegisterOperand): Deleted.
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::constantRegisters):
+        (JSC::CodeBlock::numberOfRegExps):
+        (JSC::CodeBlock::bitVectors):
+        (JSC::CodeBlock::bitVector):
+        * bytecode/HandlerInfo.h:
+        (JSC::HandlerInfoBase::typeName):
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedCodeBlock::dump):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::getConstant):
+        * bytecode/UnlinkedInstructionStream.cpp:
+        (JSC::UnlinkedInstructionStream::UnlinkedInstructionStream):
+        * bytecode/UnlinkedInstructionStream.h:
+        (JSC::UnlinkedInstructionStream::Reader::next):
+        * runtime/Options.h:
+
 2017-02-28  Mark Lam  <mark.lam@apple.com>
 
         Change JSLock to stash PlatformThread instead of std::thread::id.
index a1fa2b0..82d8d98 100644 (file)
                E3C79CAB1DB9A4DC00D1ECA4 /* DOMJITEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C79CAA1DB9A4D600D1ECA4 /* DOMJITEffect.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D239C61B829C1C00BBEF67 /* JSModuleEnvironment.cpp */; };
                E3D239C91B829C1C00BBEF67 /* JSModuleEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D239C71B829C1C00BBEF67 /* JSModuleEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E3D877731E65C09E00BE945A /* BytecodeDumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3D877711E65C08900BE945A /* BytecodeDumper.cpp */; };
+               E3D877741E65C0A000BE945A /* BytecodeDumper.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D877721E65C08900BE945A /* BytecodeDumper.h */; };
                E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */; };
                E3EF88751B66DF23003F26CB /* JSPropertyNameIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E3EF88731B66DF23003F26CB /* JSPropertyNameIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3FF75331D9CEA1800C7E16D /* DOMJITGetterSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E3D264281D38C042000BE174 /* BytecodeGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeGraph.h; sourceTree = "<group>"; };
                E3D264291D38C042000BE174 /* BytecodeRewriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeRewriter.cpp; sourceTree = "<group>"; };
                E3D2642A1D38C042000BE174 /* BytecodeRewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeRewriter.h; sourceTree = "<group>"; };
+               E3D877711E65C08900BE945A /* BytecodeDumper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeDumper.cpp; sourceTree = "<group>"; };
+               E3D877721E65C08900BE945A /* BytecodeDumper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeDumper.h; sourceTree = "<group>"; };
                E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
                E3EF88731B66DF23003F26CB /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; };
                E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITGetterSetter.h; sourceTree = "<group>"; };
                                C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */,
                                C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */,
                                0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */,
+                               E3D877711E65C08900BE945A /* BytecodeDumper.cpp */,
+                               E3D877721E65C08900BE945A /* BytecodeDumper.h */,
                                E3D264261D38C042000BE174 /* BytecodeGeneratorification.cpp */,
                                E3D264271D38C042000BE174 /* BytecodeGeneratorification.h */,
                                E3D264281D38C042000BE174 /* BytecodeGraph.h */,
                                0F0B83AB14BCF5BB00885B4F /* ExpressionRangeInfo.h in Headers */,
                                A7A8AF3817ADB5F3005AB174 /* Float32Array.h in Headers */,
                                A7A8AF3917ADB5F3005AB174 /* Float64Array.h in Headers */,
+                               E3D877741E65C0A000BE945A /* BytecodeDumper.h in Headers */,
                                0F24E54317EA9F5900ABB217 /* FPRInfo.h in Headers */,
                                E34EDBF71DB5FFC900DC87A5 /* FrameTracers.h in Headers */,
                                0F5513A61D5A682C00C32BD8 /* FreeList.h in Headers */,
                                2A05ABD51961DF2400341750 /* JSPropertyNameEnumerator.cpp in Sources */,
                                E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */,
                                862553D116136DA9009F17D0 /* JSProxy.cpp in Sources */,
+                               E3D877731E65C09E00BE945A /* BytecodeDumper.cpp in Sources */,
                                A552C37F1ADDB8FE00139726 /* JSRemoteInspector.cpp in Sources */,
                                9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */,
                                14874AE515EBDE4A002E3587 /* JSScope.cpp in Sources */,
diff --git a/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp b/Source/JavaScriptCore/bytecode/BytecodeDumper.cpp
new file mode 100644 (file)
index 0000000..3ab162e
--- /dev/null
@@ -0,0 +1,1797 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BytecodeDumper.h"
+
+#include "ArithProfile.h"
+#include "CallLinkStatus.h"
+#include "CodeBlock.h"
+#include "Error.h"
+#include "HeapInlines.h"
+#include "InterpreterInlines.h"
+#include "PolymorphicAccess.h"
+#include "PutByIdFlags.h"
+#include "StructureInlines.h"
+#include "ToThisStatus.h"
+#include "UnlinkedCodeBlock.h"
+
+namespace JSC {
+
+static StructureID getStructureID(const Instruction& instruction)
+{
+    return instruction.u.structureID;
+}
+
+static StructureID getStructureID(const UnlinkedInstruction&)
+{
+    return 0;
+}
+
+static Special::Pointer getSpecialPointer(const Instruction& instruction)
+{
+    return instruction.u.specialPointer;
+}
+
+static Special::Pointer getSpecialPointer(const UnlinkedInstruction& instruction)
+{
+    return static_cast<Special::Pointer>(instruction.u.operand);
+}
+
+static PutByIdFlags getPutByIdFlags(const Instruction& instruction)
+{
+    return instruction.u.putByIdFlags;
+}
+
+static PutByIdFlags getPutByIdFlags(const UnlinkedInstruction& instruction)
+{
+    return static_cast<PutByIdFlags>(instruction.u.operand);
+}
+
+static ToThisStatus getToThisStatus(const Instruction& instruction)
+{
+    return instruction.u.toThisStatus;
+}
+
+static ToThisStatus getToThisStatus(const UnlinkedInstruction& instruction)
+{
+    return static_cast<ToThisStatus>(instruction.u.operand);
+}
+
+static void* getPointer(const Instruction& instruction)
+{
+    return instruction.u.pointer;
+}
+
+static void* getPointer(const UnlinkedInstruction&)
+{
+    return nullptr;
+}
+
+static StructureChain* getStructureChain(const Instruction& instruction)
+{
+    return instruction.u.structureChain.get();
+}
+
+static StructureChain* getStructureChain(const UnlinkedInstruction&)
+{
+    return nullptr;
+}
+
+static Structure* getStructure(const Instruction& instruction)
+{
+    return instruction.u.structure.get();
+}
+
+static Structure* getStructure(const UnlinkedInstruction&)
+{
+    return nullptr;
+}
+
+static LLIntCallLinkInfo* getCallLinkInfo(const Instruction& instruction)
+{
+    return instruction.u.callLinkInfo;
+}
+
+static LLIntCallLinkInfo* getCallLinkInfo(const UnlinkedInstruction&)
+{
+    return nullptr;
+}
+
+static BasicBlockLocation* getBasicBlockLocation(const Instruction& instruction)
+{
+    return instruction.u.basicBlockLocation;
+}
+
+static BasicBlockLocation* getBasicBlockLocation(const UnlinkedInstruction&)
+{
+    return nullptr;
+}
+
+template<class Block>
+void* BytecodeDumper<Block>::actualPointerFor(Special::Pointer) const
+{
+    return nullptr;
+}
+
+template<>
+void* BytecodeDumper<CodeBlock>::actualPointerFor(Special::Pointer pointer) const
+{
+    return block()->globalObject()->actualPointerFor(pointer);
+}
+
+static void beginDumpProfiling(PrintStream& out, bool& hasPrintedProfiling)
+{
+    if (hasPrintedProfiling) {
+        out.print("; ");
+        return;
+    }
+
+    out.print("    ");
+    hasPrintedProfiling = true;
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpValueProfiling(PrintStream&, const typename Block::Instruction*& it, bool&)
+{
+    ++it;
+}
+
+template<>
+void BytecodeDumper<CodeBlock>::dumpValueProfiling(PrintStream& out, const typename CodeBlock::Instruction*& it, bool& hasPrintedProfiling)
+{
+    ConcurrentJSLocker locker(block()->m_lock);
+
+    ++it;
+    CString description = it->u.profile->briefDescription(locker);
+    if (!description.length())
+        return;
+    beginDumpProfiling(out, hasPrintedProfiling);
+    out.print(description);
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpArrayProfiling(PrintStream&, const typename Block::Instruction*& it, bool&)
+{
+    ++it;
+}
+
+template<>
+void BytecodeDumper<CodeBlock>::dumpArrayProfiling(PrintStream& out, const typename CodeBlock::Instruction*& it, bool& hasPrintedProfiling)
+{
+    ConcurrentJSLocker locker(block()->m_lock);
+
+    ++it;
+    if (!it->u.arrayProfile)
+        return;
+    CString description = it->u.arrayProfile->briefDescription(locker, block());
+    if (!description.length())
+        return;
+    beginDumpProfiling(out, hasPrintedProfiling);
+    out.print(description);
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpProfilesForBytecodeOffset(PrintStream&, unsigned, bool&)
+{
+}
+
+static void dumpRareCaseProfile(PrintStream& out, const char* name, RareCaseProfile* profile, bool& hasPrintedProfiling)
+{
+    if (!profile || !profile->m_counter)
+        return;
+
+    beginDumpProfiling(out, hasPrintedProfiling);
+    out.print(name, profile->m_counter);
+}
+
+static void dumpArithProfile(PrintStream& out, ArithProfile* profile, bool& hasPrintedProfiling)
+{
+    if (!profile)
+        return;
+
+    beginDumpProfiling(out, hasPrintedProfiling);
+    out.print("results: ", *profile);
+}
+
+template<>
+void BytecodeDumper<CodeBlock>::dumpProfilesForBytecodeOffset(PrintStream& out, unsigned location, bool& hasPrintedProfiling)
+{
+    dumpRareCaseProfile(out, "rare case: ", block()->rareCaseProfileForBytecodeOffset(location), hasPrintedProfiling);
+    {
+        dumpArithProfile(out, block()->arithProfileForBytecodeOffset(location), hasPrintedProfiling);
+    }
+
+#if ENABLE(DFG_JIT)
+    Vector<DFG::FrequentExitSite> exitSites = block()->exitProfile().exitSitesFor(location);
+    if (!exitSites.isEmpty()) {
+        out.print(" !! frequent exits: ");
+        CommaPrinter comma;
+        for (auto& exitSite : exitSites)
+            out.print(comma, exitSite.kind(), " ", exitSite.jitType());
+    }
+#else // ENABLE(DFG_JIT)
+    UNUSED_PARAM(location);
+#endif // ENABLE(DFG_JIT)
+}
+
+template<class Block>
+VM* BytecodeDumper<Block>::vm() const
+{
+    return block()->vm();
+}
+
+template<class Block>
+const Identifier& BytecodeDumper<Block>::identifier(int index) const
+{
+    return block()->identifier(index);
+}
+
+static CString regexpToSourceString(RegExp* regExp)
+{
+    char postfix[5] = { '/', 0, 0, 0, 0 };
+    int index = 1;
+    if (regExp->global())
+        postfix[index++] = 'g';
+    if (regExp->ignoreCase())
+        postfix[index++] = 'i';
+    if (regExp->multiline())
+        postfix[index] = 'm';
+    if (regExp->sticky())
+        postfix[index++] = 'y';
+    if (regExp->unicode())
+        postfix[index++] = 'u';
+
+    return toCString("/", regExp->pattern().impl(), postfix);
+}
+
+static CString regexpName(int re, RegExp* regexp)
+{
+    return toCString(regexpToSourceString(regexp), "(@re", re, ")");
+}
+
+template<class Instruction>
+static void printLocationAndOp(PrintStream& out, int location, const Instruction*&, const char* op)
+{
+    out.printf("[%4d] %-17s ", location, op);
+}
+
+static ALWAYS_INLINE bool isConstantRegisterIndex(int index)
+{
+    return index >= FirstConstantRegisterIndex;
+}
+
+NEVER_INLINE static const char* debugHookName(int debugHookType)
+{
+    switch (static_cast<DebugHookType>(debugHookType)) {
+    case DidEnterCallFrame:
+        return "didEnterCallFrame";
+    case WillLeaveCallFrame:
+        return "willLeaveCallFrame";
+    case WillExecuteStatement:
+        return "willExecuteStatement";
+    case WillExecuteExpression:
+        return "willExecuteExpression";
+    case WillExecuteProgram:
+        return "willExecuteProgram";
+    case DidExecuteProgram:
+        return "didExecuteProgram";
+    case DidReachBreakpoint:
+        return "didReachBreakpoint";
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+    return "";
+}
+
+template<class Block>
+CString BytecodeDumper<Block>::registerName(int r) const
+{
+    if (isConstantRegisterIndex(r))
+        return constantName(r);
+
+    return toCString(VirtualRegister(r));
+}
+
+static CString idName(int id0, const Identifier& ident)
+{
+    return toCString(ident.impl(), "(@id", id0, ")");
+}
+
+template<class Block>
+CString BytecodeDumper<Block>::constantName(int index) const
+{
+    JSValue value = block()->getConstant(index);
+    return toCString(value, "(", VirtualRegister(index), ")");
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printUnaryOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op)
+{
+    int r0 = (++it)->u.operand;
+    int r1 = (++it)->u.operand;
+
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printBinaryOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op)
+{
+    int r0 = (++it)->u.operand;
+    int r1 = (++it)->u.operand;
+    int r2 = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printConditionalJump(PrintStream& out, const typename Block::Instruction*, const typename Block::Instruction*& it, int location, const char* op)
+{
+    int r0 = (++it)->u.operand;
+    int offset = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %d(->%d)", registerName(r0).data(), offset, location + offset);
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printGetByIdOp(PrintStream& out, int location, const typename Block::Instruction*& it)
+{
+    const char* op;
+    switch (vm()->interpreter->getOpcodeID(*it)) {
+    case op_get_by_id:
+        op = "get_by_id";
+        break;
+    case op_get_by_id_proto_load:
+        op = "get_by_id_proto_load";
+        break;
+    case op_get_by_id_unset:
+        op = "get_by_id_unset";
+        break;
+    case op_get_array_length:
+        op = "array_length";
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
+        op = 0;
+#endif
+    }
+    int r0 = (++it)->u.operand;
+    int r1 = (++it)->u.operand;
+    int id0 = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
+    it += 4; // Increment up to the value profiler.
+}
+
+static void dumpStructure(PrintStream& out, const char* name, Structure* structure, const Identifier& ident)
+{
+    if (!structure)
+        return;
+
+    out.printf("%s = %p", name, structure);
+
+    PropertyOffset offset = structure->getConcurrently(ident.impl());
+    if (offset != invalidOffset)
+        out.printf(" (offset = %d)", offset);
+}
+
+static void dumpChain(PrintStream& out, StructureChain* chain, const Identifier& ident)
+{
+    out.printf("chain = %p: [", chain);
+    bool first = true;
+    for (WriteBarrier<Structure>* currentStructure = chain->head(); *currentStructure; ++currentStructure) {
+        if (first)
+            first = false;
+        else
+            out.printf(", ");
+        dumpStructure(out, "struct", currentStructure->get(), ident);
+    }
+    out.printf("]");
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map)
+{
+    const auto* instruction = instructionsBegin() + location;
+
+    const Identifier& ident = identifier(instruction[3].u.operand);
+
+    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+
+    if (vm()->interpreter->getOpcodeID(instruction[0]) == op_get_array_length)
+        out.printf(" llint(array_length)");
+    else if (StructureID structureID = getStructureID(instruction[4])) {
+        Structure* structure = vm()->heap.structureIDTable().get(structureID);
+        out.printf(" llint(");
+        dumpStructure(out, "struct", structure, ident);
+        out.printf(")");
+        if (vm()->interpreter->getOpcodeID(instruction[0]) == op_get_by_id_proto_load)
+            out.printf(" proto(%p)", getPointer(instruction[6]));
+    }
+
+#if ENABLE(JIT)
+    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
+        StructureStubInfo& stubInfo = *stubPtr;
+        if (stubInfo.resetByGC)
+            out.print(" (Reset By GC)");
+
+        out.printf(" jit(");
+
+        Structure* baseStructure = nullptr;
+        PolymorphicAccess* stub = nullptr;
+
+        switch (stubInfo.cacheType) {
+        case CacheType::GetByIdSelf:
+            out.printf("self");
+            baseStructure = stubInfo.u.byIdSelf.baseObjectStructure.get();
+            break;
+        case CacheType::Stub:
+            out.printf("stub");
+            stub = stubInfo.u.stub;
+            break;
+        case CacheType::Unset:
+            out.printf("unset");
+            break;
+        case CacheType::ArrayLength:
+            out.printf("ArrayLength");
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        if (baseStructure) {
+            out.printf(", ");
+            dumpStructure(out, "struct", baseStructure, ident);
+        }
+
+        if (stub)
+            out.print(", ", *stub);
+
+        out.printf(")");
+    }
+#else
+    UNUSED_PARAM(map);
+#endif
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map)
+{
+    const auto* instruction = instructionsBegin() + location;
+
+    const Identifier& ident = identifier(instruction[2].u.operand);
+
+    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
+
+    out.print(", ", getPutByIdFlags(instruction[8]));
+
+    if (StructureID structureID = getStructureID(instruction[4])) {
+        Structure* structure = vm()->heap.structureIDTable().get(structureID);
+        out.print(" llint(");
+        if (StructureID newStructureID = getStructureID(instruction[6])) {
+            Structure* newStructure = vm()->heap.structureIDTable().get(newStructureID);
+            dumpStructure(out, "prev", structure, ident);
+            out.print(", ");
+            dumpStructure(out, "next", newStructure, ident);
+            if (StructureChain* chain = getStructureChain(instruction[7])) {
+                out.print(", ");
+                dumpChain(out, chain, ident);
+            }
+        } else
+            dumpStructure(out, "struct", structure, ident);
+        out.print(")");
+    }
+
+#if ENABLE(JIT)
+    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
+        StructureStubInfo& stubInfo = *stubPtr;
+        if (stubInfo.resetByGC)
+            out.print(" (Reset By GC)");
+
+        out.printf(" jit(");
+
+        switch (stubInfo.cacheType) {
+        case CacheType::PutByIdReplace:
+            out.print("replace, ");
+            dumpStructure(out, "struct", stubInfo.u.byIdSelf.baseObjectStructure.get(), ident);
+            break;
+        case CacheType::Stub: {
+            out.print("stub, ", *stubInfo.u.stub);
+            break;
+        }
+        case CacheType::Unset:
+            out.printf("unset");
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        out.printf(")");
+    }
+#else
+    UNUSED_PARAM(map);
+#endif
+}
+
+#if ENABLE(JIT)
+template<typename Block>
+void BytecodeDumper<Block>::dumpCallLinkStatus(PrintStream&, unsigned, const CallLinkInfoMap&)
+{
+}
+
+template<>
+void BytecodeDumper<CodeBlock>::dumpCallLinkStatus(PrintStream& out, unsigned location, const CallLinkInfoMap& map)
+{
+    if (block()->jitType() != JITCode::FTLJIT)
+        out.print(" status(", CallLinkStatus::computeFor(block(), location, map), ")");
+}
+#endif
+
+template<class Block>
+void BytecodeDumper<Block>::printCallOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map)
+{
+    int dst = (++it)->u.operand;
+    int func = (++it)->u.operand;
+    int argCount = (++it)->u.operand;
+    int registerOffset = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.print(registerName(dst), ", ", registerName(func), ", ", argCount, ", ", registerOffset);
+    out.print(" (this at ", virtualRegisterForArgument(0, -registerOffset), ")");
+    if (cacheDumpMode == DumpCaches) {
+        LLIntCallLinkInfo* callLinkInfo = getCallLinkInfo(it[1]);
+        if (callLinkInfo->lastSeenCallee) {
+            out.printf(
+                " llint(%p, exec %p)",
+                callLinkInfo->lastSeenCallee.get(),
+                callLinkInfo->lastSeenCallee->executable());
+        }
+#if ENABLE(JIT)
+        if (CallLinkInfo* info = map.get(CodeOrigin(location))) {
+            JSFunction* target = info->lastSeenCallee();
+            if (target)
+                out.printf(" jit(%p, exec %p)", target, target->executable());
+        }
+
+        dumpCallLinkStatus(out, location, map);
+#else
+        UNUSED_PARAM(map);
+#endif
+    }
+    ++it;
+    ++it;
+    dumpArrayProfiling(out, it, hasPrintedProfiling);
+    dumpValueProfiling(out, it, hasPrintedProfiling);
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printPutByIdOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op)
+{
+    int r0 = (++it)->u.operand;
+    int id0 = (++it)->u.operand;
+    int r1 = (++it)->u.operand;
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data());
+    it += 5;
+}
+
+template<class Block>
+void BytecodeDumper<Block>::printLocationOpAndRegisterOperand(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op, int operand)
+{
+    printLocationAndOp(out, location, it, op);
+    out.printf("%s", registerName(operand).data());
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpBytecode(PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
+{
+    int location = it - begin;
+    bool hasPrintedProfiling = false;
+    OpcodeID opcode = vm()->interpreter->getOpcodeID(*it);
+    switch (opcode) {
+    case op_enter: {
+        printLocationAndOp(out, location, it, "enter");
+        break;
+    }
+    case op_get_scope: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "get_scope", r0);
+        break;
+    }
+    case op_create_direct_arguments: {
+        int r0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "create_direct_arguments");
+        out.printf("%s", registerName(r0).data());
+        break;
+    }
+    case op_create_scoped_arguments: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "create_scoped_arguments");
+        out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+        break;
+    }
+    case op_create_cloned_arguments: {
+        int r0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "create_cloned_arguments");
+        out.printf("%s", registerName(r0).data());
+        break;
+    }
+    case op_argument_count: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "argument_count", r0);
+        break;
+    }
+    case op_get_argument: {
+        int r0 = (++it)->u.operand;
+        int index = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "argument", r0);
+        out.printf(", %d", index);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_create_rest: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        unsigned argumentOffset = (++it)->u.unsignedValue;
+        printLocationAndOp(out, location, it, "create_rest");
+        out.printf("%s, %s, ", registerName(r0).data(), registerName(r1).data());
+        out.printf("ArgumentsOffset: %u", argumentOffset);
+        break;
+    }
+    case op_get_rest_length: {
+        int r0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "get_rest_length");
+        out.printf("%s, ", registerName(r0).data());
+        unsigned argumentOffset = (++it)->u.unsignedValue;
+        out.printf("ArgumentsOffset: %u", argumentOffset);
+        break;
+    }
+    case op_create_this: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        unsigned inferredInlineCapacity = (++it)->u.operand;
+        unsigned cachedFunction = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "create_this");
+        out.printf("%s, %s, %u, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity, cachedFunction);
+        break;
+    }
+    case op_to_this: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "to_this", r0);
+        Structure* structure = getStructure(*(++it));
+        if (structure)
+            out.print(", cache(struct = ", RawPointer(structure), ")");
+        out.print(", ", getToThisStatus(*(++it)));
+        break;
+    }
+    case op_check_tdz: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "op_check_tdz", r0);
+        break;
+    }
+    case op_new_object: {
+        int r0 = (++it)->u.operand;
+        unsigned inferredInlineCapacity = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_object");
+        out.printf("%s, %u", registerName(r0).data(), inferredInlineCapacity);
+        ++it; // Skip object allocation profile.
+        break;
+    }
+    case op_new_array: {
+        int dst = (++it)->u.operand;
+        int argv = (++it)->u.operand;
+        int argc = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_array");
+        out.printf("%s, %s, %d", registerName(dst).data(), registerName(argv).data(), argc);
+        ++it; // Skip array allocation profile.
+        break;
+    }
+    case op_new_array_with_spread: {
+        int dst = (++it)->u.operand;
+        int argv = (++it)->u.operand;
+        int argc = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_array_with_spread");
+        out.printf("%s, %s, %d, ", registerName(dst).data(), registerName(argv).data(), argc);
+        unsigned bitVectorIndex = (++it)->u.unsignedValue;
+        const BitVector& bitVector = block()->bitVector(bitVectorIndex);
+        out.print("BitVector:", bitVectorIndex, ":");
+        for (unsigned i = 0; i < static_cast<unsigned>(argc); i++) {
+            if (bitVector.get(i))
+                out.print("1");
+            else
+                out.print("0");
+        }
+        break;
+    }
+    case op_spread: {
+        int dst = (++it)->u.operand;
+        int arg = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "spread");
+        out.printf("%s, %s", registerName(dst).data(), registerName(arg).data());
+        break;
+    }
+    case op_new_array_with_size: {
+        int dst = (++it)->u.operand;
+        int length = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_array_with_size");
+        out.printf("%s, %s", registerName(dst).data(), registerName(length).data());
+        ++it; // Skip array allocation profile.
+        break;
+    }
+    case op_new_array_buffer: {
+        int dst = (++it)->u.operand;
+        int argv = (++it)->u.operand;
+        int argc = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_array_buffer");
+        out.printf("%s, %d, %d", registerName(dst).data(), argv, argc);
+        ++it; // Skip array allocation profile.
+        break;
+    }
+    case op_new_regexp: {
+        int r0 = (++it)->u.operand;
+        int re0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_regexp");
+        out.printf("%s, ", registerName(r0).data());
+        if (r0 >=0 && r0 < (int)block()->numberOfRegExps())
+            out.printf("%s", regexpName(re0, block()->regexp(re0)).data());
+        else
+            out.printf("bad_regexp(%d)", re0);
+        break;
+    }
+    case op_mov: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "mov");
+        out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+        break;
+    }
+    case op_profile_type: {
+        int r0 = (++it)->u.operand;
+        ++it;
+        ++it;
+        ++it;
+        ++it;
+        printLocationAndOp(out, location, it, "op_profile_type");
+        out.printf("%s", registerName(r0).data());
+        break;
+    }
+    case op_profile_control_flow: {
+        BasicBlockLocation* basicBlockLocation = getBasicBlockLocation(*(++it));
+        printLocationAndOp(out, location, it, "profile_control_flow");
+        if (basicBlockLocation)
+            out.printf("[%d, %d]", basicBlockLocation->startOffset(), basicBlockLocation->endOffset());
+        break;
+    }
+    case op_not: {
+        printUnaryOp(out, location, it, "not");
+        break;
+    }
+    case op_eq: {
+        printBinaryOp(out, location, it, "eq");
+        break;
+    }
+    case op_eq_null: {
+        printUnaryOp(out, location, it, "eq_null");
+        break;
+    }
+    case op_neq: {
+        printBinaryOp(out, location, it, "neq");
+        break;
+    }
+    case op_neq_null: {
+        printUnaryOp(out, location, it, "neq_null");
+        break;
+    }
+    case op_stricteq: {
+        printBinaryOp(out, location, it, "stricteq");
+        break;
+    }
+    case op_nstricteq: {
+        printBinaryOp(out, location, it, "nstricteq");
+        break;
+    }
+    case op_less: {
+        printBinaryOp(out, location, it, "less");
+        break;
+    }
+    case op_lesseq: {
+        printBinaryOp(out, location, it, "lesseq");
+        break;
+    }
+    case op_greater: {
+        printBinaryOp(out, location, it, "greater");
+        break;
+    }
+    case op_greatereq: {
+        printBinaryOp(out, location, it, "greatereq");
+        break;
+    }
+    case op_inc: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "inc", r0);
+        break;
+    }
+    case op_dec: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "dec", r0);
+        break;
+    }
+    case op_to_number: {
+        printUnaryOp(out, location, it, "to_number");
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_to_string: {
+        printUnaryOp(out, location, it, "to_string");
+        break;
+    }
+    case op_negate: {
+        printUnaryOp(out, location, it, "negate");
+        ++it; // op_negate has an extra operand for the ArithProfile.
+        break;
+    }
+    case op_add: {
+        printBinaryOp(out, location, it, "add");
+        ++it;
+        break;
+    }
+    case op_mul: {
+        printBinaryOp(out, location, it, "mul");
+        ++it;
+        break;
+    }
+    case op_div: {
+        printBinaryOp(out, location, it, "div");
+        ++it;
+        break;
+    }
+    case op_mod: {
+        printBinaryOp(out, location, it, "mod");
+        break;
+    }
+    case op_pow: {
+        printBinaryOp(out, location, it, "pow");
+        break;
+    }
+    case op_sub: {
+        printBinaryOp(out, location, it, "sub");
+        ++it;
+        break;
+    }
+    case op_lshift: {
+        printBinaryOp(out, location, it, "lshift");
+        break;
+    }
+    case op_rshift: {
+        printBinaryOp(out, location, it, "rshift");
+        break;
+    }
+    case op_urshift: {
+        printBinaryOp(out, location, it, "urshift");
+        break;
+    }
+    case op_bitand: {
+        printBinaryOp(out, location, it, "bitand");
+        ++it;
+        break;
+    }
+    case op_bitxor: {
+        printBinaryOp(out, location, it, "bitxor");
+        ++it;
+        break;
+    }
+    case op_bitor: {
+        printBinaryOp(out, location, it, "bitor");
+        ++it;
+        break;
+    }
+    case op_overrides_has_instance: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "overrides_has_instance");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        break;
+    }
+    case op_instanceof: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "instanceof");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        break;
+    }
+    case op_instanceof_custom: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int r3 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "instanceof_custom");
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+        break;
+    }
+    case op_unsigned: {
+        printUnaryOp(out, location, it, "unsigned");
+        break;
+    }
+    case op_typeof: {
+        printUnaryOp(out, location, it, "typeof");
+        break;
+    }
+    case op_is_empty: {
+        printUnaryOp(out, location, it, "is_empty");
+        break;
+    }
+    case op_is_undefined: {
+        printUnaryOp(out, location, it, "is_undefined");
+        break;
+    }
+    case op_is_boolean: {
+        printUnaryOp(out, location, it, "is_boolean");
+        break;
+    }
+    case op_is_number: {
+        printUnaryOp(out, location, it, "is_number");
+        break;
+    }
+    case op_is_cell_with_type: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int type = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "is_cell_with_type");
+        out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), type);
+        break;
+    }
+    case op_is_object: {
+        printUnaryOp(out, location, it, "is_object");
+        break;
+    }
+    case op_is_object_or_null: {
+        printUnaryOp(out, location, it, "is_object_or_null");
+        break;
+    }
+    case op_is_function: {
+        printUnaryOp(out, location, it, "is_function");
+        break;
+    }
+    case op_in: {
+        printBinaryOp(out, location, it, "in");
+        dumpArrayProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_try_get_by_id: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "try_get_by_id");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_get_by_id:
+    case op_get_by_id_proto_load:
+    case op_get_by_id_unset:
+    case op_get_array_length: {
+        printGetByIdOp(out, location, it);
+        printGetByIdCacheStatus(out, location, stubInfos);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_get_by_id_with_this: {
+        printLocationAndOp(out, location, it, "get_by_id_with_this");
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), idName(id0, identifier(id0)).data());
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_get_by_val_with_this: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int r3 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "get_by_val_with_this");
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_put_by_id: {
+        printPutByIdOp(out, location, it, "put_by_id");
+        printPutByIdCacheStatus(out, location, stubInfos);
+        break;
+    }
+    case op_put_by_id_with_this: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_by_id_with_this");
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), registerName(r2).data());
+        break;
+    }
+    case op_put_by_val_with_this: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int r3 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_by_val_with_this");
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+        break;
+    }
+    case op_put_getter_by_id: {
+        int r0 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        int n0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_getter_by_id");
+        out.printf("%s, %s, %d, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data());
+        break;
+    }
+    case op_put_setter_by_id: {
+        int r0 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        int n0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_setter_by_id");
+        out.printf("%s, %s, %d, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data());
+        break;
+    }
+    case op_put_getter_setter_by_id: {
+        int r0 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        int n0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_getter_setter_by_id");
+        out.printf("%s, %s, %d, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data(), registerName(r2).data());
+        break;
+    }
+    case op_put_getter_by_val: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int n0 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_getter_by_val");
+        out.printf("%s, %s, %d, %s", registerName(r0).data(), registerName(r1).data(), n0, registerName(r2).data());
+        break;
+    }
+    case op_put_setter_by_val: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int n0 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_setter_by_val");
+        out.printf("%s, %s, %d, %s", registerName(r0).data(), registerName(r1).data(), n0, registerName(r2).data());
+        break;
+    }
+    case op_define_data_property: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int r3 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "define_data_property");
+        out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
+        break;
+    }
+    case op_define_accessor_property: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        int r3 = (++it)->u.operand;
+        int r4 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "define_accessor_property");
+        out.printf("%s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data());
+        break;
+    }
+    case op_del_by_id: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "del_by_id");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
+        break;
+    }
+    case op_get_by_val: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "get_by_val");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        dumpArrayProfiling(out, it, hasPrintedProfiling);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_put_by_val: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_by_val");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        dumpArrayProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_put_by_val_direct: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_by_val_direct");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        dumpArrayProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_del_by_val: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int r2 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "del_by_val");
+        out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
+        break;
+    }
+    case op_put_by_index: {
+        int r0 = (++it)->u.operand;
+        unsigned n0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_by_index");
+        out.printf("%s, %u, %s", registerName(r0).data(), n0, registerName(r1).data());
+        break;
+    }
+    case op_jmp: {
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jmp");
+        out.printf("%d(->%d)", offset, location + offset);
+        break;
+    }
+    case op_jtrue: {
+        printConditionalJump(out, begin, it, location, "jtrue");
+        break;
+    }
+    case op_jfalse: {
+        printConditionalJump(out, begin, it, location, "jfalse");
+        break;
+    }
+    case op_jeq_null: {
+        printConditionalJump(out, begin, it, location, "jeq_null");
+        break;
+    }
+    case op_jneq_null: {
+        printConditionalJump(out, begin, it, location, "jneq_null");
+        break;
+    }
+    case op_jneq_ptr: {
+        int r0 = (++it)->u.operand;
+        Special::Pointer pointer = getSpecialPointer(*(++it));
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jneq_ptr");
+        out.printf("%s, %d (%p), %d(->%d)", registerName(r0).data(), pointer, actualPointerFor(pointer), offset, location + offset);
+        ++it;
+        break;
+    }
+    case op_jless: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jless");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jlesseq: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jlesseq");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jgreater: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jgreater");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jgreatereq: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jgreatereq");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jnless: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jnless");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jnlesseq: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jnlesseq");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jngreater: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jngreater");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_jngreatereq: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "jngreatereq");
+        out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
+        break;
+    }
+    case op_loop_hint: {
+        printLocationAndOp(out, location, it, "loop_hint");
+        break;
+    }
+    case op_check_traps: {
+        printLocationAndOp(out, location, it, "check_traps");
+        break;
+    }
+    case op_log_shadow_chicken_prologue: {
+        int r0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "log_shadow_chicken_prologue");
+        out.printf("%s", registerName(r0).data());
+        break;
+    }
+    case op_log_shadow_chicken_tail: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "log_shadow_chicken_tail");
+        out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+        break;
+    }
+    case op_switch_imm: {
+        int tableIndex = (++it)->u.operand;
+        int defaultTarget = (++it)->u.operand;
+        int scrutineeRegister = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "switch_imm");
+        out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
+        break;
+    }
+    case op_switch_char: {
+        int tableIndex = (++it)->u.operand;
+        int defaultTarget = (++it)->u.operand;
+        int scrutineeRegister = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "switch_char");
+        out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
+        break;
+    }
+    case op_switch_string: {
+        int tableIndex = (++it)->u.operand;
+        int defaultTarget = (++it)->u.operand;
+        int scrutineeRegister = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "switch_string");
+        out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
+        break;
+    }
+    case op_new_func: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_func");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_new_generator_func: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_generator_func");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_new_async_func: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_async_func");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_new_func_exp: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_func_exp");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_new_generator_func_exp: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_generator_func_exp");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_new_async_func_exp: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int f0 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "new_async_func_exp");
+        out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
+        break;
+    }
+    case op_set_function_name: {
+        int funcReg = (++it)->u.operand;
+        int nameReg = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "set_function_name");
+        out.printf("%s, %s", registerName(funcReg).data(), registerName(nameReg).data());
+        break;
+    }
+    case op_call: {
+        printCallOp(out, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
+        break;
+    }
+    case op_tail_call: {
+        printCallOp(out, location, it, "tail_call", DumpCaches, hasPrintedProfiling, callLinkInfos);
+        break;
+    }
+    case op_call_eval: {
+        printCallOp(out, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling, callLinkInfos);
+        break;
+    }
+
+    case op_construct_varargs:
+    case op_call_varargs:
+    case op_tail_call_varargs:
+    case op_tail_call_forward_arguments: {
+        int result = (++it)->u.operand;
+        int callee = (++it)->u.operand;
+        int thisValue = (++it)->u.operand;
+        int arguments = (++it)->u.operand;
+        int firstFreeRegister = (++it)->u.operand;
+        int varArgOffset = (++it)->u.operand;
+        ++it;
+        const char* opName;
+        if (opcode == op_call_varargs)
+            opName = "call_varargs";
+        else if (opcode == op_construct_varargs)
+            opName = "construct_varargs";
+        else if (opcode == op_tail_call_varargs)
+            opName = "tail_call_varargs";
+        else if (opcode == op_tail_call_forward_arguments)
+            opName = "tail_call_forward_arguments";
+        else
+            RELEASE_ASSERT_NOT_REACHED();
+
+        printLocationAndOp(out, location, it, opName);
+        out.printf("%s, %s, %s, %s, %d, %d", registerName(result).data(), registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister, varArgOffset);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+
+    case op_ret: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "ret", r0);
+        break;
+    }
+    case op_construct: {
+        printCallOp(out, location, it, "construct", DumpCaches, hasPrintedProfiling, callLinkInfos);
+        break;
+    }
+    case op_strcat: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int count = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "strcat");
+        out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), count);
+        break;
+    }
+    case op_to_primitive: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "to_primitive");
+        out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+        break;
+    }
+    case op_get_enumerable_length: {
+        int dst = it[1].u.operand;
+        int base = it[2].u.operand;
+        printLocationAndOp(out, location, it, "op_get_enumerable_length");
+        out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
+        it += OPCODE_LENGTH(op_get_enumerable_length) - 1;
+        break;
+    }
+    case op_has_indexed_property: {
+        int dst = (++it)->u.operand;
+        int base = (++it)->u.operand;
+        int propertyName = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "op_has_indexed_property");
+        out.printf("%s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data());
+        dumpArrayProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_has_structure_property: {
+        int dst = it[1].u.operand;
+        int base = it[2].u.operand;
+        int propertyName = it[3].u.operand;
+        int enumerator = it[4].u.operand;
+        printLocationAndOp(out, location, it, "op_has_structure_property");
+        out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(enumerator).data());
+        it += OPCODE_LENGTH(op_has_structure_property) - 1;
+        break;
+    }
+    case op_has_generic_property: {
+        int dst = it[1].u.operand;
+        int base = it[2].u.operand;
+        int propertyName = it[3].u.operand;
+        printLocationAndOp(out, location, it, "op_has_generic_property");
+        out.printf("%s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data());
+        it += OPCODE_LENGTH(op_has_generic_property) - 1;
+        break;
+    }
+    case op_get_direct_pname: {
+        int dst = (++it)->u.operand;
+        int base = (++it)->u.operand;
+        int propertyName = (++it)->u.operand;
+        int index = (++it)->u.operand;
+        int enumerator = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "op_get_direct_pname");
+        out.printf("%s, %s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(index).data(), registerName(enumerator).data());
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+
+    }
+    case op_get_property_enumerator: {
+        int dst = it[1].u.operand;
+        int base = it[2].u.operand;
+        printLocationAndOp(out, location, it, "op_get_property_enumerator");
+        out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
+        it += OPCODE_LENGTH(op_get_property_enumerator) - 1;
+        break;
+    }
+    case op_enumerator_structure_pname: {
+        int dst = it[1].u.operand;
+        int enumerator = it[2].u.operand;
+        int index = it[3].u.operand;
+        printLocationAndOp(out, location, it, "op_enumerator_structure_pname");
+        out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
+        it += OPCODE_LENGTH(op_enumerator_structure_pname) - 1;
+        break;
+    }
+    case op_enumerator_generic_pname: {
+        int dst = it[1].u.operand;
+        int enumerator = it[2].u.operand;
+        int index = it[3].u.operand;
+        printLocationAndOp(out, location, it, "op_enumerator_generic_pname");
+        out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
+        it += OPCODE_LENGTH(op_enumerator_generic_pname) - 1;
+        break;
+    }
+    case op_to_index_string: {
+        int dst = it[1].u.operand;
+        int index = it[2].u.operand;
+        printLocationAndOp(out, location, it, "op_to_index_string");
+        out.printf("%s, %s", registerName(dst).data(), registerName(index).data());
+        it += OPCODE_LENGTH(op_to_index_string) - 1;
+        break;
+    }
+    case op_push_with_scope: {
+        int dst = (++it)->u.operand;
+        int newScope = (++it)->u.operand;
+        int currentScope = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "push_with_scope");
+        out.printf("%s, %s, %s", registerName(dst).data(), registerName(newScope).data(), registerName(currentScope).data());
+        break;
+    }
+    case op_get_parent_scope: {
+        int dst = (++it)->u.operand;
+        int parentScope = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "get_parent_scope");
+        out.printf("%s, %s", registerName(dst).data(), registerName(parentScope).data());
+        break;
+    }
+    case op_create_lexical_environment: {
+        int dst = (++it)->u.operand;
+        int scope = (++it)->u.operand;
+        int symbolTable = (++it)->u.operand;
+        int initialValue = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "create_lexical_environment");
+        out.printf("%s, %s, %s, %s",
+            registerName(dst).data(), registerName(scope).data(), registerName(symbolTable).data(), registerName(initialValue).data());
+        break;
+    }
+    case op_catch: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "catch");
+        out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
+        break;
+    }
+    case op_throw: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "throw", r0);
+        break;
+    }
+    case op_throw_static_error: {
+        int k0 = (++it)->u.operand;
+        ErrorType k1 = static_cast<ErrorType>((++it)->u.unsignedValue);
+        printLocationAndOp(out, location, it, "throw_static_error");
+        out.printf("%s, ", constantName(k0).data());
+        out.print(k1);
+        break;
+    }
+    case op_debug: {
+        int debugHookType = (++it)->u.operand;
+        int hasBreakpointFlag = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "debug");
+        out.printf("%s, %d", debugHookName(debugHookType), hasBreakpointFlag);
+        break;
+    }
+    case op_assert: {
+        int condition = (++it)->u.operand;
+        int line = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "assert");
+        out.printf("%s, %d", registerName(condition).data(), line);
+        break;
+    }
+    case op_end: {
+        int r0 = (++it)->u.operand;
+        printLocationOpAndRegisterOperand(out, location, it, "end", r0);
+        break;
+    }
+    case op_resolve_scope: {
+        int r0 = (++it)->u.operand;
+        int scope = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        ResolveType resolveType = static_cast<ResolveType>((++it)->u.operand);
+        int depth = (++it)->u.operand;
+        void* pointer = getPointer(*(++it));
+        printLocationAndOp(out, location, it, "resolve_scope");
+        out.printf("%s, %s, %s, <%s>, %d, %p", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(), resolveTypeName(resolveType), depth, pointer);
+        break;
+    }
+    case op_get_from_scope: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
+        ++it; // Structure
+        int operand = (++it)->u.operand; // Operand
+        printLocationAndOp(out, location, it, "get_from_scope");
+        out.print(registerName(r0), ", ", registerName(r1));
+        if (static_cast<unsigned>(id0) == UINT_MAX)
+            out.print(", anonymous");
+        else
+            out.print(", ", idName(id0, identifier(id0)));
+        out.print(", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, ", operand);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_put_to_scope: {
+        int r0 = (++it)->u.operand;
+        int id0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
+        ++it; // Structure
+        int operand = (++it)->u.operand; // Operand
+        printLocationAndOp(out, location, it, "put_to_scope");
+        out.print(registerName(r0));
+        if (static_cast<unsigned>(id0) == UINT_MAX)
+            out.print(", anonymous");
+        else
+            out.print(", ", idName(id0, identifier(id0)));
+        out.print(", ", registerName(r1), ", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, <structure>, ", operand);
+        break;
+    }
+    case op_get_from_arguments: {
+        int r0 = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "get_from_arguments");
+        out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), offset);
+        dumpValueProfiling(out, it, hasPrintedProfiling);
+        break;
+    }
+    case op_put_to_arguments: {
+        int r0 = (++it)->u.operand;
+        int offset = (++it)->u.operand;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "put_to_arguments");
+        out.printf("%s, %d, %s", registerName(r0).data(), offset, registerName(r1).data());
+        break;
+    }
+    case op_yield: {
+        int r0 = (++it)->u.operand;
+        unsigned yieldPoint = (++it)->u.unsignedValue;
+        int r1 = (++it)->u.operand;
+        printLocationAndOp(out, location, it, "yield");
+        out.printf("%s, %u, %s", registerName(r0).data(), yieldPoint, registerName(r1).data());
+        break;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    dumpProfilesForBytecodeOffset(out, location, hasPrintedProfiling);
+    out.print("\n");
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpBytecode(Block* block, PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
+{
+    BytecodeDumper dumper(block, begin);
+    dumper.dumpBytecode(out, begin, it, stubInfos, callLinkInfos);
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpIdentifiers(PrintStream& out)
+{
+    if (size_t count = block()->numberOfIdentifiers()) {
+        out.printf("\nIdentifiers:\n");
+        size_t i = 0;
+        do {
+            out.printf("  id%u = %s\n", static_cast<unsigned>(i), identifier(i).string().utf8().data());
+            ++i;
+        } while (i != count);
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpConstants(PrintStream& out)
+{
+    if (!block()->constantRegisters().isEmpty()) {
+        out.printf("\nConstants:\n");
+        size_t i = 0;
+        for (const auto& constant : block()->constantRegisters()) {
+            const char* sourceCodeRepresentationDescription = nullptr;
+            switch (block()->constantsSourceCodeRepresentation()[i]) {
+            case SourceCodeRepresentation::Double:
+                sourceCodeRepresentationDescription = ": in source as double";
+                break;
+            case SourceCodeRepresentation::Integer:
+                sourceCodeRepresentationDescription = ": in source as integer";
+                break;
+            case SourceCodeRepresentation::Other:
+                sourceCodeRepresentationDescription = "";
+                break;
+            }
+            out.printf("   k%u = %s%s\n", static_cast<unsigned>(i), toCString(constant.get()).data(), sourceCodeRepresentationDescription);
+            ++i;
+        }
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpRegExps(PrintStream& out)
+{
+    if (size_t count = block()->numberOfRegExps()) {
+        out.printf("\nm_regexps:\n");
+        size_t i = 0;
+        do {
+            out.printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(block()->regexp(i)).data());
+            ++i;
+        } while (i < count);
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpExceptionHandlers(PrintStream& out)
+{
+    if (unsigned count = block()->numberOfExceptionHandlers()) {
+        out.printf("\nException Handlers:\n");
+        unsigned i = 0;
+        do {
+            const auto& handler = block()->exceptionHandler(i);
+            out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] } %s\n", i + 1, handler.start, handler.end, handler.target, handler.typeName());
+            ++i;
+        } while (i < count);
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpSwitchJumpTables(PrintStream& out)
+{
+    if (unsigned count = block()->numberOfSwitchJumpTables()) {
+        out.printf("Switch Jump Tables:\n");
+        unsigned i = 0;
+        do {
+            out.printf("  %1d = {\n", i);
+            const auto& switchJumpTable = block()->switchJumpTable(i);
+            int entry = 0;
+            auto end = switchJumpTable.branchOffsets.end();
+            for (auto iter = switchJumpTable.branchOffsets.begin(); iter != end; ++iter, ++entry) {
+                if (!*iter)
+                    continue;
+                out.printf("\t\t%4d => %04d\n", entry + switchJumpTable.min, *iter);
+            }
+            out.printf("      }\n");
+            ++i;
+        } while (i < count);
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpStringSwitchJumpTables(PrintStream& out)
+{
+    if (unsigned count = block()->numberOfStringSwitchJumpTables()) {
+        out.printf("\nString Switch Jump Tables:\n");
+        unsigned i = 0;
+        do {
+            out.printf("  %1d = {\n", i);
+            const auto& stringSwitchJumpTable = block()->stringSwitchJumpTable(i);
+            auto end = stringSwitchJumpTable.offsetTable.end();
+            for (auto iter = stringSwitchJumpTable.offsetTable.begin(); iter != end; ++iter)
+                out.printf("\t\t\"%s\" => %04d\n", iter->key->utf8().data(), iter->value.branchOffset);
+            out.printf("      }\n");
+            ++i;
+        } while (i < count);
+    }
+}
+
+template<class Block>
+void BytecodeDumper<Block>::dumpBlock(Block* block, const typename Block::UnpackedInstructions& instructions, PrintStream& out, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
+{
+    VM& vm = *block->vm();
+    size_t instructionCount = 0;
+
+    for (size_t i = 0; i < instructions.size(); i += opcodeLengths[vm.interpreter->getOpcodeID(instructions[i])])
+        ++instructionCount;
+
+    out.print(*block);
+    out.printf(
+        ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
+        static_cast<unsigned long>(instructions.size()),
+        static_cast<unsigned long>(instructions.size() * sizeof(Instruction)),
+        block->numParameters(), block->numCalleeLocals(), block->m_numVars);
+    out.print("; scope at ", block->scopeRegister());
+    out.printf("\n");
+
+    const auto* begin = instructions.begin();
+    const auto* end = instructions.end();
+    BytecodeDumper<Block> dumper(block, begin);
+    for (const auto* it = begin; it != end; ++it)
+        dumper.dumpBytecode(out, begin, it, stubInfos, callLinkInfos);
+
+    dumper.dumpIdentifiers(out);
+    dumper.dumpConstants(out);
+    dumper.dumpRegExps(out);
+    dumper.dumpExceptionHandlers(out);
+    dumper.dumpSwitchJumpTables(out);
+    dumper.dumpStringSwitchJumpTables(out);
+
+    out.printf("\n");
+}
+
+template class BytecodeDumper<UnlinkedCodeBlock>;
+template class BytecodeDumper<CodeBlock>;
+
+}
diff --git a/Source/JavaScriptCore/bytecode/BytecodeDumper.h b/Source/JavaScriptCore/bytecode/BytecodeDumper.h
new file mode 100644 (file)
index 0000000..8b2453b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CallLinkInfo.h"
+#include "StructureStubInfo.h"
+#include <wtf/StringPrintStream.h>
+
+namespace JSC {
+
+struct Instruction;
+
+template<class Block>
+class BytecodeDumper {
+public:
+    typedef typename Block::Instruction Instruction;
+
+    static void dumpBytecode(Block*, PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
+    static void dumpBlock(Block*, const typename Block::UnpackedInstructions&, PrintStream& out, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
+
+private:
+    BytecodeDumper(Block* block, const Instruction* instructionsBegin)
+        : m_block(block)
+        , m_instructionsBegin(instructionsBegin)
+    {
+    }
+
+    Block* block() const { return m_block; }
+    const Instruction* instructionsBegin() const { return m_instructionsBegin; }
+
+    ALWAYS_INLINE VM* vm() const;
+
+    CString registerName(int r) const;
+    CString constantName(int index) const;
+
+    const Identifier& identifier(int index) const;
+
+    void dumpIdentifiers(PrintStream& out);
+    void dumpConstants(PrintStream& out);
+    void dumpRegExps(PrintStream& out);
+    void dumpExceptionHandlers(PrintStream& out);
+    void dumpSwitchJumpTables(PrintStream& out);
+    void dumpStringSwitchJumpTables(PrintStream& out);
+
+    void printUnaryOp(PrintStream& out, int location, const Instruction*& it, const char* op);
+    void printBinaryOp(PrintStream& out, int location, const Instruction*& it, const char* op);
+    void printConditionalJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op);
+    void printGetByIdOp(PrintStream& out, int location, const Instruction*& it);
+    void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
+    void printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&);
+    enum CacheDumpMode { DumpCaches, DontDumpCaches };
+    void printCallOp(PrintStream& out, int location, const Instruction*& it, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&);
+    void printPutByIdOp(PrintStream& out, int location, const Instruction*& it, const char* op);
+    void printLocationOpAndRegisterOperand(PrintStream& out, int location, const Instruction*& it, const char* op, int operand);
+    void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap&, const CallLinkInfoMap&);
+
+    void dumpValueProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling);
+    void dumpArrayProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling);
+    void dumpProfilesForBytecodeOffset(PrintStream&, unsigned location, bool& hasPrintedProfiling);
+
+    void* actualPointerFor(Special::Pointer) const;
+
+#if ENABLE(JIT)
+    void dumpCallLinkStatus(PrintStream&, unsigned location, const CallLinkInfoMap&);
+#endif
+
+    Block* m_block;
+    const Instruction* m_instructionsBegin;
+};
+
+}
index f7e1e9a..949afa6 100644 (file)
@@ -27,6 +27,7 @@
 #include "config.h"
 #include "BytecodeGeneratorification.h"
 
+#include "BytecodeDumper.h"
 #include "BytecodeLivenessAnalysisInlines.h"
 #include "BytecodeRewriter.h"
 #include "BytecodeUseDef.h"
@@ -66,7 +67,7 @@ public:
                 }
 
                 case op_yield: {
-                    unsigned liveCalleeLocalsIndex = pc[2].u.index;
+                    unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue;
                     if (liveCalleeLocalsIndex >= m_yields.size())
                         m_yields.resize(liveCalleeLocalsIndex + 1);
                     YieldData& data = m_yields[liveCalleeLocalsIndex];
@@ -261,6 +262,9 @@ void BytecodeGeneratorification::run()
 
 void performGeneratorification(UnlinkedCodeBlock* codeBlock, UnlinkedCodeBlock::UnpackedInstructions& instructions, SymbolTable* generatorFrameSymbolTable, int generatorFrameSymbolTableIndex)
 {
+    if (Options::dumpBytecodesBeforeGeneratorification())
+        BytecodeDumper<UnlinkedCodeBlock>::dumpBlock(codeBlock, instructions, WTF::dataFile());
+
     BytecodeGeneratorification pass(codeBlock, instructions, generatorFrameSymbolTable, generatorFrameSymbolTableIndex);
     pass.run();
 }
index 60eeb71..8168d87 100644 (file)
@@ -194,7 +194,7 @@ void BytecodeLivenessAnalysis::dumpResults()
             FastBitVector liveBefore = getLivenessInfoAtBytecodeOffset(bytecodeOffset);
             dumpBitVector(liveBefore);
             dataLogF("\n");
-            codeBlock->dumpBytecode(WTF::dataFile(), codeBlock->globalObject()->globalExec(), instructionsBegin, currentInstruction);
+            codeBlock->dumpBytecode(WTF::dataFile(), instructionsBegin, currentInstruction);
 
             OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode);
             unsigned opcodeLength = opcodeLengths[opcodeID];
index cd97f34..6161f1b 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "ArithProfile.h"
 #include "BasicBlockLocation.h"
+#include "BytecodeDumper.h"
 #include "BytecodeGenerator.h"
 #include "BytecodeLivenessAnalysis.h"
 #include "BytecodeUseDef.h"
@@ -49,7 +50,7 @@
 #include "FunctionExecutableDump.h"
 #include "GetPutInfo.h"
 #include "InlineCallFrame.h"
-#include "Interpreter.h"
+#include "InterpreterInlines.h"
 #include "JIT.h"
 #include "JITMathIC.h"
 #include "JSCInlines.h"
@@ -204,324 +205,6 @@ void CodeBlock::dump(PrintStream& out) const
     dumpAssumingJITType(out, jitType());
 }
 
-static CString idName(int id0, const Identifier& ident)
-{
-    return toCString(ident.impl(), "(@id", id0, ")");
-}
-
-CString CodeBlock::registerName(int r) const
-{
-    if (isConstantRegisterIndex(r))
-        return constantName(r);
-
-    return toCString(VirtualRegister(r));
-}
-
-CString CodeBlock::constantName(int index) const
-{
-    JSValue value = getConstant(index);
-    return toCString(value, "(", VirtualRegister(index), ")");
-}
-
-static CString regexpToSourceString(RegExp* regExp)
-{
-    char postfix[5] = { '/', 0, 0, 0, 0 };
-    int index = 1;
-    if (regExp->global())
-        postfix[index++] = 'g';
-    if (regExp->ignoreCase())
-        postfix[index++] = 'i';
-    if (regExp->multiline())
-        postfix[index] = 'm';
-    if (regExp->sticky())
-        postfix[index++] = 'y';
-    if (regExp->unicode())
-        postfix[index++] = 'u';
-
-    return toCString("/", regExp->pattern().impl(), postfix);
-}
-
-static CString regexpName(int re, RegExp* regexp)
-{
-    return toCString(regexpToSourceString(regexp), "(@re", re, ")");
-}
-
-NEVER_INLINE static const char* debugHookName(int debugHookType)
-{
-    switch (static_cast<DebugHookType>(debugHookType)) {
-        case DidEnterCallFrame:
-            return "didEnterCallFrame";
-        case WillLeaveCallFrame:
-            return "willLeaveCallFrame";
-        case WillExecuteStatement:
-            return "willExecuteStatement";
-        case WillExecuteExpression:
-            return "willExecuteExpression";
-        case WillExecuteProgram:
-            return "willExecuteProgram";
-        case DidExecuteProgram:
-            return "didExecuteProgram";
-        case DidReachBreakpoint:
-            return "didReachBreakpoint";
-    }
-
-    RELEASE_ASSERT_NOT_REACHED();
-    return "";
-}
-
-void CodeBlock::printUnaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
-{
-    int r0 = (++it)->u.operand;
-    int r1 = (++it)->u.operand;
-
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-}
-
-void CodeBlock::printBinaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
-{
-    int r0 = (++it)->u.operand;
-    int r1 = (++it)->u.operand;
-    int r2 = (++it)->u.operand;
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-}
-
-void CodeBlock::printConditionalJump(PrintStream& out, ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op)
-{
-    int r0 = (++it)->u.operand;
-    int offset = (++it)->u.operand;
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s, %d(->%d)", registerName(r0).data(), offset, location + offset);
-}
-
-void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it)
-{
-    const char* op;
-    switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
-    case op_get_by_id:
-        op = "get_by_id";
-        break;
-    case op_get_by_id_proto_load:
-        op = "get_by_id_proto_load";
-        break;
-    case op_get_by_id_unset:
-        op = "get_by_id_unset";
-        break;
-    case op_get_array_length:
-        op = "array_length";
-        break;
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
-        op = 0;
-#endif
-    }
-    int r0 = (++it)->u.operand;
-    int r1 = (++it)->u.operand;
-    int id0 = (++it)->u.operand;
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
-    it += 4; // Increment up to the value profiler.
-}
-
-static void dumpStructure(PrintStream& out, const char* name, Structure* structure, const Identifier& ident)
-{
-    if (!structure)
-        return;
-    
-    out.printf("%s = %p", name, structure);
-    
-    PropertyOffset offset = structure->getConcurrently(ident.impl());
-    if (offset != invalidOffset)
-        out.printf(" (offset = %d)", offset);
-}
-
-static void dumpChain(PrintStream& out, StructureChain* chain, const Identifier& ident)
-{
-    out.printf("chain = %p: [", chain);
-    bool first = true;
-    for (WriteBarrier<Structure>* currentStructure = chain->head();
-         *currentStructure;
-         ++currentStructure) {
-        if (first)
-            first = false;
-        else
-            out.printf(", ");
-        dumpStructure(out, "struct", currentStructure->get(), ident);
-    }
-    out.printf("]");
-}
-
-void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int location, const StubInfoMap& map)
-{
-    Instruction* instruction = instructions().begin() + location;
-
-    const Identifier& ident = identifier(instruction[3].u.operand);
-    
-    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
-    
-    if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
-        out.printf(" llint(array_length)");
-    else if (StructureID structureID = instruction[4].u.structureID) {
-        Structure* structure = m_vm->heap.structureIDTable().get(structureID);
-        out.printf(" llint(");
-        dumpStructure(out, "struct", structure, ident);
-        out.printf(")");
-        if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_by_id_proto_load)
-            out.printf(" proto(%p)", instruction[6].u.pointer);
-    }
-
-#if ENABLE(JIT)
-    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
-        StructureStubInfo& stubInfo = *stubPtr;
-        if (stubInfo.resetByGC)
-            out.print(" (Reset By GC)");
-        
-        out.printf(" jit(");
-            
-        Structure* baseStructure = nullptr;
-        PolymorphicAccess* stub = nullptr;
-            
-        switch (stubInfo.cacheType) {
-        case CacheType::GetByIdSelf:
-            out.printf("self");
-            baseStructure = stubInfo.u.byIdSelf.baseObjectStructure.get();
-            break;
-        case CacheType::Stub:
-            out.printf("stub");
-            stub = stubInfo.u.stub;
-            break;
-        case CacheType::Unset:
-            out.printf("unset");
-            break;
-        case CacheType::ArrayLength:
-            out.printf("ArrayLength");
-            break;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
-        }
-            
-        if (baseStructure) {
-            out.printf(", ");
-            dumpStructure(out, "struct", baseStructure, ident);
-        }
-
-        if (stub)
-            out.print(", ", *stub);
-
-        out.printf(")");
-    }
-#else
-    UNUSED_PARAM(map);
-#endif
-}
-
-void CodeBlock::printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map)
-{
-    Instruction* instruction = instructions().begin() + location;
-
-    const Identifier& ident = identifier(instruction[2].u.operand);
-    
-    UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
-
-    out.print(", ", instruction[8].u.putByIdFlags);
-    
-    if (StructureID structureID = instruction[4].u.structureID) {
-        Structure* structure = m_vm->heap.structureIDTable().get(structureID);
-        out.print(" llint(");
-        if (StructureID newStructureID = instruction[6].u.structureID) {
-            Structure* newStructure = m_vm->heap.structureIDTable().get(newStructureID);
-            dumpStructure(out, "prev", structure, ident);
-            out.print(", ");
-            dumpStructure(out, "next", newStructure, ident);
-            if (StructureChain* chain = instruction[7].u.structureChain.get()) {
-                out.print(", ");
-                dumpChain(out, chain, ident);
-            }
-        } else
-            dumpStructure(out, "struct", structure, ident);
-        out.print(")");
-    }
-
-#if ENABLE(JIT)
-    if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
-        StructureStubInfo& stubInfo = *stubPtr;
-        if (stubInfo.resetByGC)
-            out.print(" (Reset By GC)");
-        
-        out.printf(" jit(");
-        
-        switch (stubInfo.cacheType) {
-        case CacheType::PutByIdReplace:
-            out.print("replace, ");
-            dumpStructure(out, "struct", stubInfo.u.byIdSelf.baseObjectStructure.get(), ident);
-            break;
-        case CacheType::Stub: {
-            out.print("stub, ", *stubInfo.u.stub);
-            break;
-        }
-        case CacheType::Unset:
-            out.printf("unset");
-            break;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
-        }
-        out.printf(")");
-    }
-#else
-    UNUSED_PARAM(map);
-#endif
-}
-
-void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map)
-{
-    int dst = (++it)->u.operand;
-    int func = (++it)->u.operand;
-    int argCount = (++it)->u.operand;
-    int registerOffset = (++it)->u.operand;
-    printLocationAndOp(out, exec, location, it, op);
-    out.print(registerName(dst), ", ", registerName(func), ", ", argCount, ", ", registerOffset);
-    out.print(" (this at ", virtualRegisterForArgument(0, -registerOffset), ")");
-    if (cacheDumpMode == DumpCaches) {
-        LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
-        if (callLinkInfo->lastSeenCallee) {
-            out.printf(
-                " llint(%p, exec %p)",
-                callLinkInfo->lastSeenCallee.get(),
-                callLinkInfo->lastSeenCallee->executable());
-        }
-#if ENABLE(JIT)
-        if (CallLinkInfo* info = map.get(CodeOrigin(location))) {
-            JSFunction* target = info->lastSeenCallee();
-            if (target)
-                out.printf(" jit(%p, exec %p)", target, target->executable());
-        }
-        
-        if (jitType() != JITCode::FTLJIT)
-            out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")");
-#else
-        UNUSED_PARAM(map);
-#endif
-    }
-    ++it;
-    ++it;
-    dumpArrayProfiling(out, it, hasPrintedProfiling);
-    dumpValueProfiling(out, it, hasPrintedProfiling);
-}
-
-void CodeBlock::printPutByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
-{
-    int r0 = (++it)->u.operand;
-    int id0 = (++it)->u.operand;
-    int r1 = (++it)->u.operand;
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data());
-    it += 5;
-}
-
 void CodeBlock::dumpSource()
 {
     dumpSource(WTF::dataFile());
@@ -549,1244 +232,24 @@ void CodeBlock::dumpBytecode()
 
 void CodeBlock::dumpBytecode(PrintStream& out)
 {
-    // We only use the ExecState* for things that don't actually lead to JS execution,
-    // like converting a JSString to a String. Hence the globalExec is appropriate.
-    ExecState* exec = m_globalObject->globalExec();
-    
-    size_t instructionCount = 0;
-
-    for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
-        ++instructionCount;
-
-    out.print(*this);
-    out.printf(
-        ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
-        static_cast<unsigned long>(instructions().size()),
-        static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
-        m_numParameters, m_numCalleeLocals, m_numVars);
-    out.print("; scope at ", scopeRegister());
-    out.printf("\n");
-    
     StubInfoMap stubInfos;
     CallLinkInfoMap callLinkInfos;
     getStubInfoMap(stubInfos);
     getCallLinkInfoMap(callLinkInfos);
-    
-    const Instruction* begin = instructions().begin();
-    const Instruction* end = instructions().end();
-    for (const Instruction* it = begin; it != end; ++it)
-        dumpBytecode(out, exec, begin, it, stubInfos, callLinkInfos);
-    
-    if (numberOfIdentifiers()) {
-        out.printf("\nIdentifiers:\n");
-        size_t i = 0;
-        do {
-            out.printf("  id%u = %s\n", static_cast<unsigned>(i), identifier(i).string().utf8().data());
-            ++i;
-        } while (i != numberOfIdentifiers());
-    }
-
-    if (!m_constantRegisters.isEmpty()) {
-        out.printf("\nConstants:\n");
-        size_t i = 0;
-        do {
-            const char* sourceCodeRepresentationDescription = nullptr;
-            switch (m_constantsSourceCodeRepresentation[i]) {
-            case SourceCodeRepresentation::Double:
-                sourceCodeRepresentationDescription = ": in source as double";
-                break;
-            case SourceCodeRepresentation::Integer:
-                sourceCodeRepresentationDescription = ": in source as integer";
-                break;
-            case SourceCodeRepresentation::Other:
-                sourceCodeRepresentationDescription = "";
-                break;
-            }
-            out.printf("   k%u = %s%s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data(), sourceCodeRepresentationDescription);
-            ++i;
-        } while (i < m_constantRegisters.size());
-    }
-
-    if (size_t count = m_unlinkedCode->numberOfRegExps()) {
-        out.printf("\nm_regexps:\n");
-        size_t i = 0;
-        do {
-            out.printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).data());
-            ++i;
-        } while (i < count);
-    }
-
-    dumpExceptionHandlers(out);
-    
-    if (m_rareData && !m_rareData->m_switchJumpTables.isEmpty()) {
-        out.printf("Switch Jump Tables:\n");
-        unsigned i = 0;
-        do {
-            out.printf("  %1d = {\n", i);
-            int entry = 0;
-            Vector<int32_t>::const_iterator end = m_rareData->m_switchJumpTables[i].branchOffsets.end();
-            for (Vector<int32_t>::const_iterator iter = m_rareData->m_switchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
-                if (!*iter)
-                    continue;
-                out.printf("\t\t%4d => %04d\n", entry + m_rareData->m_switchJumpTables[i].min, *iter);
-            }
-            out.printf("      }\n");
-            ++i;
-        } while (i < m_rareData->m_switchJumpTables.size());
-    }
-    
-    if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
-        out.printf("\nString Switch Jump Tables:\n");
-        unsigned i = 0;
-        do {
-            out.printf("  %1d = {\n", i);
-            StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
-            for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
-                out.printf("\t\t\"%s\" => %04d\n", iter->key->utf8().data(), iter->value.branchOffset);
-            out.printf("      }\n");
-            ++i;
-        } while (i < m_rareData->m_stringSwitchJumpTables.size());
-    }
-
-    out.printf("\n");
-}
-
-void CodeBlock::dumpExceptionHandlers(PrintStream& out)
-{
-    if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
-        out.printf("\nException Handlers:\n");
-        unsigned i = 0;
-        do {
-            HandlerInfo& handler = m_rareData->m_exceptionHandlers[i];
-            out.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] } %s\n",
-                i + 1, handler.start, handler.end, handler.target, handler.typeName());
-            ++i;
-        } while (i < m_rareData->m_exceptionHandlers.size());
-    }
-}
-
-void CodeBlock::beginDumpProfiling(PrintStream& out, bool& hasPrintedProfiling)
-{
-    if (hasPrintedProfiling) {
-        out.print("; ");
-        return;
-    }
-    
-    out.print("    ");
-    hasPrintedProfiling = true;
-}
-
-void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
-{
-    ConcurrentJSLocker locker(m_lock);
-    
-    ++it;
-    CString description = it->u.profile->briefDescription(locker);
-    if (!description.length())
-        return;
-    beginDumpProfiling(out, hasPrintedProfiling);
-    out.print(description);
-}
-
-void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
-{
-    ConcurrentJSLocker locker(m_lock);
-    
-    ++it;
-    if (!it->u.arrayProfile)
-        return;
-    CString description = it->u.arrayProfile->briefDescription(locker, this);
-    if (!description.length())
-        return;
-    beginDumpProfiling(out, hasPrintedProfiling);
-    out.print(description);
-}
-
-void CodeBlock::dumpRareCaseProfile(PrintStream& out, const char* name, RareCaseProfile* profile, bool& hasPrintedProfiling)
-{
-    if (!profile || !profile->m_counter)
-        return;
-
-    beginDumpProfiling(out, hasPrintedProfiling);
-    out.print(name, profile->m_counter);
-}
-
-void CodeBlock::dumpArithProfile(PrintStream& out, ArithProfile* profile, bool& hasPrintedProfiling)
-{
-    if (!profile)
-        return;
-    
-    beginDumpProfiling(out, hasPrintedProfiling);
-    out.print("results: ", *profile);
-}
-
-void CodeBlock::printLocationAndOp(PrintStream& out, ExecState*, int location, const Instruction*&, const char* op)
-{
-    out.printf("[%4d] %-17s ", location, op);
-}
-
-void CodeBlock::printLocationOpAndRegisterOperand(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, int operand)
-{
-    printLocationAndOp(out, exec, location, it, op);
-    out.printf("%s", registerName(operand).data());
+    BytecodeDumper<CodeBlock>::dumpBlock(this, instructions(), out, stubInfos, callLinkInfos);
 }
 
-void CodeBlock::dumpBytecode(
-    PrintStream& out, ExecState* exec, const Instruction* begin, const Instruction*& it,
-    const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
+void CodeBlock::dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
 {
-    int location = it - begin;
-    bool hasPrintedProfiling = false;
-    OpcodeID opcode = exec->interpreter()->getOpcodeID(it->u.opcode);
-    switch (opcode) {
-        case op_enter: {
-            printLocationAndOp(out, exec, location, it, "enter");
-            break;
-        }
-        case op_get_scope: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "get_scope", r0);
-            break;
-        }
-        case op_create_direct_arguments: {
-            int r0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "create_direct_arguments");
-            out.printf("%s", registerName(r0).data());
-            break;
-        }
-        case op_create_scoped_arguments: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "create_scoped_arguments");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            break;
-        }
-        case op_create_cloned_arguments: {
-            int r0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "create_cloned_arguments");
-            out.printf("%s", registerName(r0).data());
-            break;
-        }
-        case op_argument_count: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "argument_count", r0);
-            break;
-        }
-        case op_get_argument: {
-            int r0 = (++it)->u.operand;
-            int index = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "argument", r0);
-            out.printf(", %d", index);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_create_rest: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            unsigned argumentOffset = (++it)->u.unsignedValue;
-            printLocationAndOp(out, exec, location, it, "create_rest");
-            out.printf("%s, %s, ", registerName(r0).data(), registerName(r1).data());
-            out.printf("ArgumentsOffset: %u", argumentOffset);
-            break;
-        }
-        case op_get_rest_length: {
-            int r0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "get_rest_length");
-            out.printf("%s, ", registerName(r0).data());
-            unsigned argumentOffset = (++it)->u.unsignedValue;
-            out.printf("ArgumentsOffset: %u", argumentOffset);
-            break;
-        }
-        case op_create_this: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            unsigned inferredInlineCapacity = (++it)->u.operand;
-            unsigned cachedFunction = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "create_this");
-            out.printf("%s, %s, %u, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity, cachedFunction);
-            break;
-        }
-        case op_to_this: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "to_this", r0);
-            Structure* structure = (++it)->u.structure.get();
-            if (structure)
-                out.print(", cache(struct = ", RawPointer(structure), ")");
-            out.print(", ", (++it)->u.toThisStatus);
-            break;
-        }
-        case op_check_tdz: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "op_check_tdz", r0);
-            break;
-        }
-        case op_new_object: {
-            int r0 = (++it)->u.operand;
-            unsigned inferredInlineCapacity = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_object");
-            out.printf("%s, %u", registerName(r0).data(), inferredInlineCapacity);
-            ++it; // Skip object allocation profile.
-            break;
-        }
-        case op_new_array: {
-            int dst = (++it)->u.operand;
-            int argv = (++it)->u.operand;
-            int argc = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_array");
-            out.printf("%s, %s, %d", registerName(dst).data(), registerName(argv).data(), argc);
-            ++it; // Skip array allocation profile.
-            break;
-        }
-        case op_new_array_with_spread: {
-            int dst = (++it)->u.operand;
-            int argv = (++it)->u.operand;
-            int argc = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_array_with_spread");
-            out.printf("%s, %s, %d, ", registerName(dst).data(), registerName(argv).data(), argc);
-            unsigned bitVectorIndex = (++it)->u.unsignedValue;
-            const BitVector& bitVector = m_unlinkedCode->bitVector(bitVectorIndex);
-            out.print("BitVector:", bitVectorIndex, ":");
-            for (unsigned i = 0; i < static_cast<unsigned>(argc); i++) {
-                if (bitVector.get(i))
-                    out.print("1");
-                else
-                    out.print("0");
-            }
-            break;
-        }
-        case op_spread: {
-            int dst = (++it)->u.operand;
-            int arg = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "spread");
-            out.printf("%s, %s", registerName(dst).data(), registerName(arg).data());
-            break;
-        }
-        case op_new_array_with_size: {
-            int dst = (++it)->u.operand;
-            int length = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_array_with_size");
-            out.printf("%s, %s", registerName(dst).data(), registerName(length).data());
-            ++it; // Skip array allocation profile.
-            break;
-        }
-        case op_new_array_buffer: {
-            int dst = (++it)->u.operand;
-            int argv = (++it)->u.operand;
-            int argc = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_array_buffer");
-            out.printf("%s, %d, %d", registerName(dst).data(), argv, argc);
-            ++it; // Skip array allocation profile.
-            break;
-        }
-        case op_new_regexp: {
-            int r0 = (++it)->u.operand;
-            int re0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_regexp");
-            out.printf("%s, ", registerName(r0).data());
-            if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps())
-                out.printf("%s", regexpName(re0, regexp(re0)).data());
-            else
-                out.printf("bad_regexp(%d)", re0);
-            break;
-        }
-        case op_mov: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "mov");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            break;
-        }
-        case op_profile_type: {
-            int r0 = (++it)->u.operand;
-            ++it;
-            ++it;
-            ++it;
-            ++it;
-            printLocationAndOp(out, exec, location, it, "op_profile_type");
-            out.printf("%s", registerName(r0).data());
-            break;
-        }
-        case op_profile_control_flow: {
-            BasicBlockLocation* basicBlockLocation = (++it)->u.basicBlockLocation;
-            printLocationAndOp(out, exec, location, it, "profile_control_flow");
-            out.printf("[%d, %d]", basicBlockLocation->startOffset(), basicBlockLocation->endOffset());
-            break;
-        }
-        case op_not: {
-            printUnaryOp(out, exec, location, it, "not");
-            break;
-        }
-        case op_eq: {
-            printBinaryOp(out, exec, location, it, "eq");
-            break;
-        }
-        case op_eq_null: {
-            printUnaryOp(out, exec, location, it, "eq_null");
-            break;
-        }
-        case op_neq: {
-            printBinaryOp(out, exec, location, it, "neq");
-            break;
-        }
-        case op_neq_null: {
-            printUnaryOp(out, exec, location, it, "neq_null");
-            break;
-        }
-        case op_stricteq: {
-            printBinaryOp(out, exec, location, it, "stricteq");
-            break;
-        }
-        case op_nstricteq: {
-            printBinaryOp(out, exec, location, it, "nstricteq");
-            break;
-        }
-        case op_less: {
-            printBinaryOp(out, exec, location, it, "less");
-            break;
-        }
-        case op_lesseq: {
-            printBinaryOp(out, exec, location, it, "lesseq");
-            break;
-        }
-        case op_greater: {
-            printBinaryOp(out, exec, location, it, "greater");
-            break;
-        }
-        case op_greatereq: {
-            printBinaryOp(out, exec, location, it, "greatereq");
-            break;
-        }
-        case op_inc: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "inc", r0);
-            break;
-        }
-        case op_dec: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "dec", r0);
-            break;
-        }
-        case op_to_number: {
-            printUnaryOp(out, exec, location, it, "to_number");
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_to_string: {
-            printUnaryOp(out, exec, location, it, "to_string");
-            break;
-        }
-        case op_negate: {
-            printUnaryOp(out, exec, location, it, "negate");
-            ++it; // op_negate has an extra operand for the ArithProfile.
-            break;
-        }
-        case op_add: {
-            printBinaryOp(out, exec, location, it, "add");
-            ++it;
-            break;
-        }
-        case op_mul: {
-            printBinaryOp(out, exec, location, it, "mul");
-            ++it;
-            break;
-        }
-        case op_div: {
-            printBinaryOp(out, exec, location, it, "div");
-            ++it;
-            break;
-        }
-        case op_mod: {
-            printBinaryOp(out, exec, location, it, "mod");
-            break;
-        }
-        case op_pow: {
-            printBinaryOp(out, exec, location, it, "pow");
-            break;
-        }
-        case op_sub: {
-            printBinaryOp(out, exec, location, it, "sub");
-            ++it;
-            break;
-        }
-        case op_lshift: {
-            printBinaryOp(out, exec, location, it, "lshift");
-            break;            
-        }
-        case op_rshift: {
-            printBinaryOp(out, exec, location, it, "rshift");
-            break;
-        }
-        case op_urshift: {
-            printBinaryOp(out, exec, location, it, "urshift");
-            break;
-        }
-        case op_bitand: {
-            printBinaryOp(out, exec, location, it, "bitand");
-            ++it;
-            break;
-        }
-        case op_bitxor: {
-            printBinaryOp(out, exec, location, it, "bitxor");
-            ++it;
-            break;
-        }
-        case op_bitor: {
-            printBinaryOp(out, exec, location, it, "bitor");
-            ++it;
-            break;
-        }
-        case op_overrides_has_instance: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "overrides_has_instance");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            break;
-        }
-        case op_instanceof: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "instanceof");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            break;
-        }
-        case op_instanceof_custom: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int r3 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "instanceof_custom");
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
-            break;
-        }
-        case op_unsigned: {
-            printUnaryOp(out, exec, location, it, "unsigned");
-            break;
-        }
-        case op_typeof: {
-            printUnaryOp(out, exec, location, it, "typeof");
-            break;
-        }
-        case op_is_empty: {
-            printUnaryOp(out, exec, location, it, "is_empty");
-            break;
-        }
-        case op_is_undefined: {
-            printUnaryOp(out, exec, location, it, "is_undefined");
-            break;
-        }
-        case op_is_boolean: {
-            printUnaryOp(out, exec, location, it, "is_boolean");
-            break;
-        }
-        case op_is_number: {
-            printUnaryOp(out, exec, location, it, "is_number");
-            break;
-        }
-        case op_is_cell_with_type: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int type = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "is_cell_with_type");
-            out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), type);
-            break;
-        }
-        case op_is_object: {
-            printUnaryOp(out, exec, location, it, "is_object");
-            break;
-        }
-        case op_is_object_or_null: {
-            printUnaryOp(out, exec, location, it, "is_object_or_null");
-            break;
-        }
-        case op_is_function: {
-            printUnaryOp(out, exec, location, it, "is_function");
-            break;
-        }
-        case op_in: {
-            printBinaryOp(out, exec, location, it, "in");
-            dumpArrayProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_try_get_by_id: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "try_get_by_id");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_get_by_id:
-        case op_get_by_id_proto_load:
-        case op_get_by_id_unset:
-        case op_get_array_length: {
-            printGetByIdOp(out, exec, location, it);
-            printGetByIdCacheStatus(out, exec, location, stubInfos);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_get_by_id_with_this: {
-            printLocationAndOp(out, exec, location, it, "get_by_id_with_this");
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), idName(id0, identifier(id0)).data());
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_get_by_val_with_this: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int r3 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "get_by_val_with_this");
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_put_by_id: {
-            printPutByIdOp(out, exec, location, it, "put_by_id");
-            printPutByIdCacheStatus(out, location, stubInfos);
-            break;
-        }
-        case op_put_by_id_with_this: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_by_id_with_this");
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(), registerName(r2).data());
-            break;
-        }
-        case op_put_by_val_with_this: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int r3 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_by_val_with_this");
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
-            break;
-        }
-        case op_put_getter_by_id: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int n0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_getter_by_id");
-            out.printf("%s, %s, %d, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data());
-            break;
-        }
-        case op_put_setter_by_id: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int n0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_setter_by_id");
-            out.printf("%s, %s, %d, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data());
-            break;
-        }
-        case op_put_getter_setter_by_id: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int n0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_getter_setter_by_id");
-            out.printf("%s, %s, %d, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), n0, registerName(r1).data(), registerName(r2).data());
-            break;
-        }
-        case op_put_getter_by_val: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int n0 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_getter_by_val");
-            out.printf("%s, %s, %d, %s", registerName(r0).data(), registerName(r1).data(), n0, registerName(r2).data());
-            break;
-        }
-        case op_put_setter_by_val: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int n0 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_setter_by_val");
-            out.printf("%s, %s, %d, %s", registerName(r0).data(), registerName(r1).data(), n0, registerName(r2).data());
-            break;
-        }
-        case op_define_data_property: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int r3 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "define_data_property");
-            out.printf("%s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data());
-            break;
-        }
-        case op_define_accessor_property: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            int r3 = (++it)->u.operand;
-            int r4 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "define_accessor_property");
-            out.printf("%s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data());
-            break;
-        }
-        case op_del_by_id: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "del_by_id");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
-            break;
-        }
-        case op_get_by_val: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "get_by_val");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            dumpArrayProfiling(out, it, hasPrintedProfiling);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_put_by_val: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_by_val");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            dumpArrayProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_put_by_val_direct: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_by_val_direct");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            dumpArrayProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_del_by_val: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int r2 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "del_by_val");
-            out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
-            break;
-        }
-        case op_put_by_index: {
-            int r0 = (++it)->u.operand;
-            unsigned n0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_by_index");
-            out.printf("%s, %u, %s", registerName(r0).data(), n0, registerName(r1).data());
-            break;
-        }
-        case op_jmp: {
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jmp");
-            out.printf("%d(->%d)", offset, location + offset);
-            break;
-        }
-        case op_jtrue: {
-            printConditionalJump(out, exec, begin, it, location, "jtrue");
-            break;
-        }
-        case op_jfalse: {
-            printConditionalJump(out, exec, begin, it, location, "jfalse");
-            break;
-        }
-        case op_jeq_null: {
-            printConditionalJump(out, exec, begin, it, location, "jeq_null");
-            break;
-        }
-        case op_jneq_null: {
-            printConditionalJump(out, exec, begin, it, location, "jneq_null");
-            break;
-        }
-        case op_jneq_ptr: {
-            int r0 = (++it)->u.operand;
-            Special::Pointer pointer = (++it)->u.specialPointer;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jneq_ptr");
-            out.printf("%s, %d (%p), %d(->%d)", registerName(r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset);
-            ++it;
-            break;
-        }
-        case op_jless: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jless");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jlesseq: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jlesseq");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jgreater: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jgreater");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jgreatereq: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jgreatereq");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jnless: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jnless");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jnlesseq: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jnlesseq");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jngreater: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jngreater");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_jngreatereq: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "jngreatereq");
-            out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
-            break;
-        }
-        case op_loop_hint: {
-            printLocationAndOp(out, exec, location, it, "loop_hint");
-            break;
-        }
-        case op_check_traps: {
-            printLocationAndOp(out, exec, location, it, "check_traps");
-            break;
-        }
-        case op_log_shadow_chicken_prologue: {
-            int r0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "log_shadow_chicken_prologue");
-            out.printf("%s", registerName(r0).data());
-            break;
-        }
-        case op_log_shadow_chicken_tail: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "log_shadow_chicken_tail");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            break;
-        }
-        case op_switch_imm: {
-            int tableIndex = (++it)->u.operand;
-            int defaultTarget = (++it)->u.operand;
-            int scrutineeRegister = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "switch_imm");
-            out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
-            break;
-        }
-        case op_switch_char: {
-            int tableIndex = (++it)->u.operand;
-            int defaultTarget = (++it)->u.operand;
-            int scrutineeRegister = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "switch_char");
-            out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
-            break;
-        }
-        case op_switch_string: {
-            int tableIndex = (++it)->u.operand;
-            int defaultTarget = (++it)->u.operand;
-            int scrutineeRegister = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "switch_string");
-            out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
-            break;
-        }
-        case op_new_func: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_func");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_new_generator_func: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_generator_func");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_new_async_func: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_async_func");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_new_func_exp: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_func_exp");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_new_generator_func_exp: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_generator_func_exp");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_new_async_func_exp: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int f0 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "new_async_func_exp");
-            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
-            break;
-        }
-        case op_set_function_name: {
-            int funcReg = (++it)->u.operand;
-            int nameReg = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "set_function_name");
-            out.printf("%s, %s", registerName(funcReg).data(), registerName(nameReg).data());
-            break;
-        }
-        case op_call: {
-            printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
-            break;
-        }
-        case op_tail_call: {
-            printCallOp(out, exec, location, it, "tail_call", DumpCaches, hasPrintedProfiling, callLinkInfos);
-            break;
-        }
-        case op_call_eval: {
-            printCallOp(out, exec, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling, callLinkInfos);
-            break;
-        }
-            
-        case op_construct_varargs:
-        case op_call_varargs:
-        case op_tail_call_varargs:
-        case op_tail_call_forward_arguments: {
-            int result = (++it)->u.operand;
-            int callee = (++it)->u.operand;
-            int thisValue = (++it)->u.operand;
-            int arguments = (++it)->u.operand;
-            int firstFreeRegister = (++it)->u.operand;
-            int varArgOffset = (++it)->u.operand;
-            ++it;
-            const char* opName;
-            if (opcode == op_call_varargs)
-                opName = "call_varargs";
-            else if (opcode == op_construct_varargs)
-                opName = "construct_varargs";
-            else if (opcode == op_tail_call_varargs)
-                opName = "tail_call_varargs";
-            else if (opcode == op_tail_call_forward_arguments)
-                opName = "tail_call_forward_arguments";
-            else
-                RELEASE_ASSERT_NOT_REACHED();
-
-            printLocationAndOp(out, exec, location, it, opName);
-            out.printf("%s, %s, %s, %s, %d, %d", registerName(result).data(), registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister, varArgOffset);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-
-        case op_ret: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "ret", r0);
-            break;
-        }
-        case op_construct: {
-            printCallOp(out, exec, location, it, "construct", DumpCaches, hasPrintedProfiling, callLinkInfos);
-            break;
-        }
-        case op_strcat: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int count = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "strcat");
-            out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), count);
-            break;
-        }
-        case op_to_primitive: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "to_primitive");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            break;
-        }
-        case op_get_enumerable_length: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_get_enumerable_length");
-            out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
-            it += OPCODE_LENGTH(op_get_enumerable_length) - 1;
-            break;
-        }
-        case op_has_indexed_property: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            int propertyName = it[3].u.operand;
-            ArrayProfile* arrayProfile = it[4].u.arrayProfile;
-            printLocationAndOp(out, exec, location, it, "op_has_indexed_property");
-            out.printf("%s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), arrayProfile);
-            it += OPCODE_LENGTH(op_has_indexed_property) - 1;
-            break;
-        }
-        case op_has_structure_property: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            int propertyName = it[3].u.operand;
-            int enumerator = it[4].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_has_structure_property");
-            out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(enumerator).data());
-            it += OPCODE_LENGTH(op_has_structure_property) - 1;
-            break;
-        }
-        case op_has_generic_property: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            int propertyName = it[3].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_has_generic_property");
-            out.printf("%s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data());
-            it += OPCODE_LENGTH(op_has_generic_property) - 1;
-            break;
-        }
-        case op_get_direct_pname: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            int propertyName = it[3].u.operand;
-            int index = it[4].u.operand;
-            int enumerator = it[5].u.operand;
-            ValueProfile* profile = it[6].u.profile;
-            printLocationAndOp(out, exec, location, it, "op_get_direct_pname");
-            out.printf("%s, %s, %s, %s, %s, %p", registerName(dst).data(), registerName(base).data(), registerName(propertyName).data(), registerName(index).data(), registerName(enumerator).data(), profile);
-            it += OPCODE_LENGTH(op_get_direct_pname) - 1;
-            break;
-
-        }
-        case op_get_property_enumerator: {
-            int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_get_property_enumerator");
-            out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
-            it += OPCODE_LENGTH(op_get_property_enumerator) - 1;
-            break;
-        }
-        case op_enumerator_structure_pname: {
-            int dst = it[1].u.operand;
-            int enumerator = it[2].u.operand;
-            int index = it[3].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_enumerator_structure_pname");
-            out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
-            it += OPCODE_LENGTH(op_enumerator_structure_pname) - 1;
-            break;
-        }
-        case op_enumerator_generic_pname: {
-            int dst = it[1].u.operand;
-            int enumerator = it[2].u.operand;
-            int index = it[3].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_enumerator_generic_pname");
-            out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
-            it += OPCODE_LENGTH(op_enumerator_generic_pname) - 1;
-            break;
-        }
-        case op_to_index_string: {
-            int dst = it[1].u.operand;
-            int index = it[2].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_to_index_string");
-            out.printf("%s, %s", registerName(dst).data(), registerName(index).data());
-            it += OPCODE_LENGTH(op_to_index_string) - 1;
-            break;
-        }
-        case op_push_with_scope: {
-            int dst = (++it)->u.operand;
-            int newScope = (++it)->u.operand;
-            int currentScope = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "push_with_scope");
-            out.printf("%s, %s, %s", registerName(dst).data(), registerName(newScope).data(), registerName(currentScope).data());
-            break;
-        }
-        case op_get_parent_scope: {
-            int dst = (++it)->u.operand;
-            int parentScope = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "get_parent_scope");
-            out.printf("%s, %s", registerName(dst).data(), registerName(parentScope).data());
-            break;
-        }
-        case op_create_lexical_environment: {
-            int dst = (++it)->u.operand;
-            int scope = (++it)->u.operand;
-            int symbolTable = (++it)->u.operand;
-            int initialValue = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "create_lexical_environment");
-            out.printf("%s, %s, %s, %s", 
-                registerName(dst).data(), registerName(scope).data(), registerName(symbolTable).data(), registerName(initialValue).data());
-            break;
-        }
-        case op_catch: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "catch");
-            out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
-            break;
-        }
-        case op_throw: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "throw", r0);
-            break;
-        }
-        case op_throw_static_error: {
-            int k0 = (++it)->u.operand;
-            ErrorType k1 = static_cast<ErrorType>((++it)->u.unsignedValue);
-            printLocationAndOp(out, exec, location, it, "throw_static_error");
-            out.printf("%s, ", constantName(k0).data());
-            out.print(k1);
-            break;
-        }
-        case op_debug: {
-            int debugHookType = (++it)->u.operand;
-            int hasBreakpointFlag = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "debug");
-            out.printf("%s, %d", debugHookName(debugHookType), hasBreakpointFlag);
-            break;
-        }
-        case op_assert: {
-            int condition = (++it)->u.operand;
-            int line = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "assert");
-            out.printf("%s, %d", registerName(condition).data(), line);
-            break;
-        }
-        case op_end: {
-            int r0 = (++it)->u.operand;
-            printLocationOpAndRegisterOperand(out, exec, location, it, "end", r0);
-            break;
-        }
-        case op_resolve_scope: {
-            int r0 = (++it)->u.operand;
-            int scope = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            ResolveType resolveType = static_cast<ResolveType>((++it)->u.operand);
-            int depth = (++it)->u.operand;
-            void* pointer = (++it)->u.pointer;
-            printLocationAndOp(out, exec, location, it, "resolve_scope");
-            out.printf("%s, %s, %s, <%s>, %d, %p", registerName(r0).data(), registerName(scope).data(), idName(id0, identifier(id0)).data(), resolveTypeName(resolveType), depth, pointer);
-            break;
-        }
-        case op_get_from_scope: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
-            ++it; // Structure
-            int operand = (++it)->u.operand; // Operand
-            printLocationAndOp(out, exec, location, it, "get_from_scope");
-            out.print(registerName(r0), ", ", registerName(r1));
-            if (static_cast<unsigned>(id0) == UINT_MAX)
-                out.print(", anonymous");
-            else
-                out.print(", ", idName(id0, identifier(id0)));
-            out.print(", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, ", operand);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_put_to_scope: {
-            int r0 = (++it)->u.operand;
-            int id0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            GetPutInfo getPutInfo = GetPutInfo((++it)->u.operand);
-            ++it; // Structure
-            int operand = (++it)->u.operand; // Operand
-            printLocationAndOp(out, exec, location, it, "put_to_scope");
-            out.print(registerName(r0));
-            if (static_cast<unsigned>(id0) == UINT_MAX)
-                out.print(", anonymous");
-            else
-                out.print(", ", idName(id0, identifier(id0)));
-            out.print(", ", registerName(r1), ", ", getPutInfo.operand(), "<", resolveModeName(getPutInfo.resolveMode()), "|", resolveTypeName(getPutInfo.resolveType()), "|", initializationModeName(getPutInfo.initializationMode()), ">, <structure>, ", operand);
-            break;
-        }
-        case op_get_from_arguments: {
-            int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "get_from_arguments");
-            out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), offset);
-            dumpValueProfiling(out, it, hasPrintedProfiling);
-            break;
-        }
-        case op_put_to_arguments: {
-            int r0 = (++it)->u.operand;
-            int offset = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            printLocationAndOp(out, exec, location, it, "put_to_arguments");
-            out.printf("%s, %d, %s", registerName(r0).data(), offset, registerName(r1).data());
-            break;
-        }
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-    }
-
-    dumpRareCaseProfile(out, "rare case: ", rareCaseProfileForBytecodeOffset(location), hasPrintedProfiling);
-    {
-        dumpArithProfile(out, arithProfileForBytecodeOffset(location), hasPrintedProfiling);
-    }
-    
-#if ENABLE(DFG_JIT)
-    Vector<DFG::FrequentExitSite> exitSites = exitProfile().exitSitesFor(location);
-    if (!exitSites.isEmpty()) {
-        out.print(" !! frequent exits: ");
-        CommaPrinter comma;
-        for (auto& exitSite : exitSites)
-            out.print(comma, exitSite.kind(), " ", exitSite.jitType());
-    }
-#else // ENABLE(DFG_JIT)
-    UNUSED_PARAM(location);
-#endif // ENABLE(DFG_JIT)
-    out.print("\n");
+    BytecodeDumper<CodeBlock>::dumpBytecode(this, out, begin, it, stubInfos, callLinkInfos);
 }
 
 void CodeBlock::dumpBytecode(
     PrintStream& out, unsigned bytecodeOffset,
     const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
 {
-    ExecState* exec = m_globalObject->globalExec();
     const Instruction* it = instructions().begin() + bytecodeOffset;
-    dumpBytecode(out, exec, instructions().begin(), it, stubInfos, callLinkInfos);
+    dumpBytecode(out, instructions().begin(), it, stubInfos, callLinkInfos);
 }
 
 #define FOR_EACH_MEMBER_VECTOR(macro) \
@@ -2320,7 +783,7 @@ void CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         }
 
         case op_debug: {
-            if (pc[1].u.index == DidReachBreakpoint)
+            if (pc[1].u.unsignedValue == DidReachBreakpoint)
                 m_hasDebuggerStatement = true;
             break;
         }
@@ -2647,7 +1110,7 @@ void CodeBlock::propagateTransitions(const ConcurrentJSLocker&, SlotVisitor& vis
         const Vector<unsigned>& propertyAccessInstructions = m_unlinkedCode->propertyAccessInstructions();
         for (size_t i = 0; i < propertyAccessInstructions.size(); ++i) {
             Instruction* instruction = &instructions()[propertyAccessInstructions[i]];
-            switch (interpreter->getOpcodeID(instruction[0].u.opcode)) {
+            switch (interpreter->getOpcodeID(instruction[0])) {
             case op_put_by_id: {
                 StructureID oldStructureID = instruction[4].u.structureID;
                 StructureID newStructureID = instruction[6].u.structureID;
@@ -2781,7 +1244,7 @@ void CodeBlock::finalizeLLIntInlineCaches()
     const Vector<unsigned>& propertyAccessInstructions = m_unlinkedCode->propertyAccessInstructions();
     for (size_t size = propertyAccessInstructions.size(), i = 0; i < size; ++i) {
         Instruction* curInstruction = &instructions()[propertyAccessInstructions[i]];
-        switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
+        switch (interpreter->getOpcodeID(curInstruction[0])) {
         case op_get_by_id:
         case op_get_by_id_proto_load:
         case op_get_by_id_unset: {
@@ -2859,7 +1322,7 @@ void CodeBlock::finalizeLLIntInlineCaches()
             break;
         }
         default:
-            OpcodeID opcodeID = interpreter->getOpcodeID(curInstruction[0].u.opcode);
+            OpcodeID opcodeID = interpreter->getOpcodeID(curInstruction[0]);
             ASSERT_WITH_MESSAGE_UNUSED(opcodeID, false, "Unhandled opcode in CodeBlock::finalizeUnconditionally, %s(%d) at bc %u", opcodeNames[opcodeID], opcodeID, propertyAccessInstructions[i]);
         }
     }
@@ -3241,7 +1704,7 @@ bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column)
     const Instruction* begin = instructions().begin();
     const Instruction* end = instructions().end();
     for (const Instruction* it = begin; it != end;) {
-        OpcodeID opcodeID = interpreter->getOpcodeID(it->u.opcode);
+        OpcodeID opcodeID = interpreter->getOpcodeID(*it);
         if (opcodeID == op_debug) {
             unsigned bytecodeOffset = it - begin;
             int unused;
@@ -4188,7 +2651,7 @@ bool CodeBlock::usesOpcode(OpcodeID opcodeID)
     unsigned instructionCount = instructions().size();
     
     for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
-        switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
+        switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset])) {
 #define DEFINE_OP(curOpcode, length)        \
         case curOpcode:                     \
             if (curOpcode == opcodeID)      \
@@ -4233,7 +2696,7 @@ String CodeBlock::nameForRegister(VirtualRegister virtualRegister)
 
 ValueProfile* CodeBlock::valueProfileForBytecodeOffset(int bytecodeOffset)
 {
-    OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(instructions()[bytecodeOffset].u.opcode);
+    OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(instructions()[bytecodeOffset]);
     unsigned length = opcodeLength(opcodeID);
     return instructions()[bytecodeOffset + length - 1].u.profile;
 }
@@ -4322,7 +2785,7 @@ ArithProfile* CodeBlock::arithProfileForBytecodeOffset(int bytecodeOffset)
 
 ArithProfile* CodeBlock::arithProfileForPC(Instruction* pc)
 {
-    auto opcodeID = vm()->interpreter->getOpcodeID(pc[0].u.opcode);
+    auto opcodeID = vm()->interpreter->getOpcodeID(pc[0]);
     switch (opcodeID) {
     case op_negate:
         return bitwise_cast<ArithProfile*>(&pc[3].u.operand);
@@ -4369,12 +2832,12 @@ void CodeBlock::insertBasicBlockBoundariesForControlFlowProfiler(RefCountedArray
         // Because op_profile_control_flow is emitted at the beginning of every basic block, finding 
         // the next op_profile_control_flow will give us the text range of a single basic block.
         size_t startIdx = bytecodeOffsets[i];
-        RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[startIdx].u.opcode) == op_profile_control_flow);
+        RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[startIdx]) == op_profile_control_flow);
         int basicBlockStartOffset = instructions[startIdx + 1].u.operand;
         int basicBlockEndOffset;
         if (i + 1 < offsetsLength) {
             size_t endIdx = bytecodeOffsets[i + 1];
-            RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[endIdx].u.opcode) == op_profile_control_flow);
+            RELEASE_ASSERT(vm()->interpreter->getOpcodeID(instructions[endIdx]) == op_profile_control_flow);
             basicBlockEndOffset = instructions[endIdx + 1].u.operand - 1;
         } else {
             basicBlockEndOffset = m_sourceOffset + ownerScriptExecutable()->source().length() - 1; // Offset before the closing brace.
index 1942ea2..bdc33d6 100644 (file)
@@ -191,9 +191,9 @@ public:
 
     void dumpBytecode();
     void dumpBytecode(PrintStream&);
-    void dumpBytecode(
-        PrintStream&, unsigned bytecodeOffset,
-        const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
+    void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
+    void dumpBytecode(PrintStream& out, unsigned bytecodeOffset, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
+
     void dumpExceptionHandlers(PrintStream&);
     void printStructures(PrintStream&, const Instruction*);
     void printStructure(PrintStream&, const char* name, const Instruction*, int operand);
@@ -542,6 +542,7 @@ public:
         return result;
     }
 
+    const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
     WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
     static ALWAYS_INLINE bool isConstantRegisterIndex(int index) { return index >= FirstConstantRegisterIndex; }
     ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
@@ -552,6 +553,10 @@ public:
     FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }
     
     RegExp* regexp(int index) const { return m_unlinkedCode->regexp(index); }
+    unsigned numberOfRegExps() const { return m_unlinkedCode->numberOfRegExps(); }
+
+    const Vector<BitVector>& bitVectors() const { return m_unlinkedCode->bitVectors(); }
+    const BitVector& bitVector(size_t i) { return m_unlinkedCode->bitVector(i); }
 
     unsigned numberOfConstantBuffers() const
     {
@@ -917,30 +922,6 @@ private:
         m_constantRegisters[index - FirstConstantRegisterIndex].set(m_globalObject->vm(), this, value);
     }
 
-    void dumpBytecode(
-        PrintStream&, ExecState*, const Instruction* begin, const Instruction*&,
-        const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
-
-    CString registerName(int r) const;
-    CString constantName(int index) const;
-    void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
-    void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
-    void printConditionalJump(PrintStream&, ExecState*, const Instruction*, const Instruction*&, int location, const char* op);
-    void printGetByIdOp(PrintStream&, ExecState*, int location, const Instruction*&);
-    void printGetByIdCacheStatus(PrintStream&, ExecState*, int location, const StubInfoMap&);
-    enum CacheDumpMode { DumpCaches, DontDumpCaches };
-    void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&);
-    void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
-    void printPutByIdCacheStatus(PrintStream&, int location, const StubInfoMap&);
-    void printLocationAndOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
-    void printLocationOpAndRegisterOperand(PrintStream&, ExecState*, int location, const Instruction*& it, const char* op, int operand);
-
-    void beginDumpProfiling(PrintStream&, bool& hasPrintedProfiling);
-    void dumpValueProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling);
-    void dumpArrayProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling);
-    void dumpRareCaseProfile(PrintStream&, const char* name, RareCaseProfile*, bool& hasPrintedProfiling);
-    void dumpArithProfile(PrintStream&, ArithProfile*, bool& hasPrintedProfiling);
-
     bool shouldVisitStrongly(const ConcurrentJSLocker&);
     bool shouldJettisonDueToWeakReference();
     bool shouldJettisonDueToOldAge(const ConcurrentJSLocker&);
index 752defe..ad7e74c 100644 (file)
@@ -46,7 +46,7 @@ struct HandlerInfoBase {
     HandlerType type() const { return static_cast<HandlerType>(typeBits); }
     void setType(HandlerType type) { typeBits = static_cast<uint32_t>(type); }
 
-    const char* typeName()
+    const char* typeName() const
     {
         switch (type()) {
         case HandlerType::Catch:
index 53defbf..1c71aa6 100644 (file)
@@ -413,4 +413,8 @@ void UnlinkedCodeBlock::shrinkToFit()
     }
 }
 
+void UnlinkedCodeBlock::dump(PrintStream&) const
+{
+}
+
 } // namespace JSC
index f057497..f9c9c37 100644 (file)
@@ -104,7 +104,7 @@ struct UnlinkedInstruction {
     union {
         OpcodeID opcode;
         int32_t operand;
-        unsigned index;
+        unsigned unsignedValue;
     } u;
 };
 
@@ -215,6 +215,7 @@ public:
     const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; }
     const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
     ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
+    ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
     const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
 
     // Jumps
@@ -380,6 +381,8 @@ public:
     TriState didOptimize() const { return m_didOptimize; }
     void setDidOptimize(TriState didOptimize) { m_didOptimize = didOptimize; }
 
+    void dump(PrintStream&) const;
+
 protected:
     UnlinkedCodeBlock(VM*, Structure*, CodeType, const ExecutableInfo&, DebuggerMode);
     ~UnlinkedCodeBlock();
index e8762ff..48c816a 100644 (file)
@@ -95,7 +95,7 @@ UnlinkedInstructionStream::UnlinkedInstructionStream(const Vector<UnlinkedInstru
         unsigned opLength = opcodeLength(opcode);
 
         for (unsigned j = 1; j < opLength; ++j)
-            append32(ptr, pc[j].u.index);
+            append32(ptr, pc[j].u.unsignedValue);
 
         i += opLength;
     }
index ef139ad..8c0bf57 100644 (file)
@@ -142,7 +142,7 @@ ALWAYS_INLINE const UnlinkedInstruction* UnlinkedInstructionStream::Reader::next
     m_unpackedBuffer[0].u.opcode = static_cast<OpcodeID>(read8());
     unsigned opLength = opcodeLength(m_unpackedBuffer[0].u.opcode);
     for (unsigned i = 1; i < opLength; ++i)
-        m_unpackedBuffer[i].u.index = read32();
+        m_unpackedBuffer[i].u.unsignedValue = read32();
     return m_unpackedBuffer;
 }
 
index 01adf07..b3370a3 100644 (file)
@@ -132,6 +132,7 @@ typedef const char* optionString;
     v(bool, dumpBytecodeLivenessResults, false, Normal, nullptr) \
     v(bool, validateBytecode, false, Normal, nullptr) \
     v(bool, forceDebuggerBytecodeGeneration, false, Normal, nullptr) \
+    v(bool, dumpBytecodesBeforeGeneratorification, false, Normal, nullptr) \
     \
     v(bool, useFunctionDotArguments, true, Normal, nullptr) \
     v(bool, useTailCalls, true, Normal, nullptr) \