Add $vm debugging tool.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Apr 2015 00:25:14 +0000 (00:25 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Apr 2015 00:25:14 +0000 (00:25 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143809

Reviewed by Geoffrey Garen.

For debugging VM bugs, it would be useful to be able to dump VM data structures
from JS code that we instrument.  To this end, let's introduce a
JS_enableDollarVM option that, if true, installs an $vm property into each JS
global object at creation time.  The $vm property refers to an object that
provides a collection of useful utility functions.  For this initial
implementation, $vm will have the following:

    crash() - trigger an intentional crash.

    dfgTrue() - returns true if the current function is DFG compiled, else returns false.
    jitTrue() - returns true if the current function is compiled by the baseline JIT, else returns false.
    llintTrue() - returns true if the current function is interpreted by the LLINT, else returns false.

    gc() - runs a full GC.
    edenGC() - runs an eden GC.

    codeBlockForFrame(frameNumber) - gets the codeBlock at the specified frame (0 = current, 1 = caller, etc).
    printSourceFor(codeBlock) - prints the source code for the codeBlock.
    printByteCodeFor(codeBlock) - prints the bytecode for the codeBlock.

    print(str) - prints a string to dataLog output.
    printCallFrame() - prints the current CallFrame.
    printStack() - prints the JS stack.
    printInternal(value) - prints the JSC internal info for the specified value.

With JS_enableDollarVM=true, JS code can use the above functions like so:

    $vm.print("Using $vm features\n");

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printCallOp):
- FTL compiled functions don't like it when we try to compute the CallLinkStatus.
  Hence, we skip this step if we're dumping an FTL codeBlock.

* heap/Heap.cpp:
(JSC::Heap::collectAndSweep):
(JSC::Heap::collectAllGarbage): Deleted.
* heap/Heap.h:
(JSC::Heap::collectAllGarbage):
- Add ability to do an Eden collection and sweep.

* interpreter/StackVisitor.cpp:
(JSC::printIndents):
(JSC::log):
(JSC::logF):
(JSC::StackVisitor::Frame::print):
(JSC::jitTypeName): Deleted.
(JSC::printif): Deleted.
- Modernize the implementation of StackVisitor::Frame::print(), and remove some
  now redundant code.
- Also fix it so that it downgrades gracefully when encountering inlined DFG
  and compiled FTL functions.

(DebugPrintFrameFunctor::DebugPrintFrameFunctor): Deleted.
(DebugPrintFrameFunctor::operator()): Deleted.
(debugPrintCallFrame): Deleted.
(debugPrintStack): Deleted.
- these have been moved into JSDollarVMPrototype.cpp.

* interpreter/StackVisitor.h:
- StackVisitor::Frame::print() is now enabled for release builds as well so that
  we can call it from $vm.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
- Added the $vm instance to global objects conditional on the JSC_enableDollarVM
  option.

* runtime/Options.h:
- Added the JSC_enableDollarVM option.

* tools/JSDollarVM.cpp: Added.
* tools/JSDollarVM.h: Added.
(JSC::JSDollarVM::createStructure):
(JSC::JSDollarVM::create):
(JSC::JSDollarVM::JSDollarVM):

* tools/JSDollarVMPrototype.cpp: Added.
- This file contains 2 sets of functions:

  a. a C++ implementation of debugging utility functions that are callable when
     doing debugging from lldb.  To the extent possible, these functions try to
     be cautious and not cause unintended crashes should the user call them with
     the wrong info.  Hence, they are designed to be robust rather than speedy.

  b. the native implementations of JS functions in the $vm object.  Where there
     is overlapping functionality, these are built on top of the C++ functions
     above to do the work.

  Note: it does not make sense for all of the $vm functions to have a C++
  counterpart for lldb debugging.  For example, the $vm.dfgTrue() function is
  only useful for JS code, and works via the DFG intrinsics mechanism.
  When doing debugging via lldb, the optimization level of the currently
  executing JS function can be gotten by dumping the current CallFrame instead.

(JSC::currentThreadOwnsJSLock):
(JSC::ensureCurrentThreadOwnsJSLock):
(JSC::JSDollarVMPrototype::addFunction):
(JSC::functionCrash): - $vm.crash()
(JSC::functionDFGTrue): - $vm.dfgTrue()
(JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
(JSC::CallerFrameJITTypeFunctor::operator()):
(JSC::CallerFrameJITTypeFunctor::jitType):
(JSC::functionLLintTrue): - $vm.llintTrue()
(JSC::functionJITTrue): - $vm.jitTrue()
(JSC::gc):
(JSC::functionGC): - $vm.gc()
(JSC::edenGC):
(JSC::functionEdenGC): - $vm.edenGC()
(JSC::isValidCodeBlock):
(JSC::codeBlockForFrame):
(JSC::functionCodeBlockForFrame): - $vm.codeBlockForFrame(frameNumber)
(JSC::codeBlockFromArg):
(JSC::functionPrintSourceFor): - $vm.printSourceFor(codeBlock)
(JSC::functionPrintByteCodeFor): - $vm.printBytecodeFor(codeBlock)
(JSC::functionPrint): - $vm.print(str)
(JSC::PrintFrameFunctor::PrintFrameFunctor):
(JSC::PrintFrameFunctor::operator()):
(JSC::printCallFrame):
(JSC::printStack):
(JSC::functionPrintCallFrame): - $vm.printCallFrame()
(JSC::functionPrintStack): - $vm.printStack()
(JSC::printValue):
(JSC::functionPrintValue): - $vm.printValue()
(JSC::JSDollarVMPrototype::finishCreation):
* tools/JSDollarVMPrototype.h: Added.
(JSC::JSDollarVMPrototype::create):
(JSC::JSDollarVMPrototype::createStructure):
(JSC::JSDollarVMPrototype::JSDollarVMPrototype):

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

17 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/interpreter/StackVisitor.cpp
Source/JavaScriptCore/interpreter/StackVisitor.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/Options.h
Source/JavaScriptCore/tools/JSDollarVM.cpp [new file with mode: 0644]
Source/JavaScriptCore/tools/JSDollarVM.h [new file with mode: 0644]
Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp [new file with mode: 0644]
Source/JavaScriptCore/tools/JSDollarVMPrototype.h [new file with mode: 0644]

index 9cfc5a6..fbce0b6 100644 (file)
@@ -389,6 +389,8 @@ set(JavaScriptCore_SOURCES
     tools/CodeProfile.cpp
     tools/CodeProfiling.cpp
     tools/FunctionOverrides.cpp
+    tools/JSDollarVM.cpp
+    tools/JSDollarVMPrototype.cpp
 
     yarr/RegularExpression.cpp
     yarr/YarrCanonicalizeUCS2.cpp
index da30431..cd9355f 100644 (file)
@@ -1,3 +1,146 @@
+2015-04-16  Mark Lam  <mark.lam@apple.com>
+
+        Add $vm debugging tool.
+        https://bugs.webkit.org/show_bug.cgi?id=143809
+
+        Reviewed by Geoffrey Garen.
+
+        For debugging VM bugs, it would be useful to be able to dump VM data structures
+        from JS code that we instrument.  To this end, let's introduce a
+        JS_enableDollarVM option that, if true, installs an $vm property into each JS
+        global object at creation time.  The $vm property refers to an object that
+        provides a collection of useful utility functions.  For this initial
+        implementation, $vm will have the following:
+
+            crash() - trigger an intentional crash.
+
+            dfgTrue() - returns true if the current function is DFG compiled, else returns false.
+            jitTrue() - returns true if the current function is compiled by the baseline JIT, else returns false.
+            llintTrue() - returns true if the current function is interpreted by the LLINT, else returns false.
+
+            gc() - runs a full GC.
+            edenGC() - runs an eden GC.
+
+            codeBlockForFrame(frameNumber) - gets the codeBlock at the specified frame (0 = current, 1 = caller, etc).
+            printSourceFor(codeBlock) - prints the source code for the codeBlock.
+            printByteCodeFor(codeBlock) - prints the bytecode for the codeBlock.
+
+            print(str) - prints a string to dataLog output.
+            printCallFrame() - prints the current CallFrame.
+            printStack() - prints the JS stack.
+            printInternal(value) - prints the JSC internal info for the specified value.
+
+        With JS_enableDollarVM=true, JS code can use the above functions like so:
+
+            $vm.print("Using $vm features\n");
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printCallOp):
+        - FTL compiled functions don't like it when we try to compute the CallLinkStatus.
+          Hence, we skip this step if we're dumping an FTL codeBlock.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::collectAndSweep):
+        (JSC::Heap::collectAllGarbage): Deleted.
+        * heap/Heap.h:
+        (JSC::Heap::collectAllGarbage):
+        - Add ability to do an Eden collection and sweep.
+
+        * interpreter/StackVisitor.cpp:
+        (JSC::printIndents):
+        (JSC::log):
+        (JSC::logF):
+        (JSC::StackVisitor::Frame::print):
+        (JSC::jitTypeName): Deleted.
+        (JSC::printif): Deleted.
+        - Modernize the implementation of StackVisitor::Frame::print(), and remove some
+          now redundant code.
+        - Also fix it so that it downgrades gracefully when encountering inlined DFG
+          and compiled FTL functions.
+
+        (DebugPrintFrameFunctor::DebugPrintFrameFunctor): Deleted.
+        (DebugPrintFrameFunctor::operator()): Deleted.
+        (debugPrintCallFrame): Deleted.
+        (debugPrintStack): Deleted.
+        - these have been moved into JSDollarVMPrototype.cpp. 
+
+        * interpreter/StackVisitor.h:
+        - StackVisitor::Frame::print() is now enabled for release builds as well so that
+          we can call it from $vm.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        - Added the $vm instance to global objects conditional on the JSC_enableDollarVM
+          option.
+
+        * runtime/Options.h:
+        - Added the JSC_enableDollarVM option.
+
+        * tools/JSDollarVM.cpp: Added.
+        * tools/JSDollarVM.h: Added.
+        (JSC::JSDollarVM::createStructure):
+        (JSC::JSDollarVM::create):
+        (JSC::JSDollarVM::JSDollarVM):
+
+        * tools/JSDollarVMPrototype.cpp: Added.
+        - This file contains 2 sets of functions:
+
+          a. a C++ implementation of debugging utility functions that are callable when
+             doing debugging from lldb.  To the extent possible, these functions try to
+             be cautious and not cause unintended crashes should the user call them with
+             the wrong info.  Hence, they are designed to be robust rather than speedy.
+
+          b. the native implementations of JS functions in the $vm object.  Where there
+             is overlapping functionality, these are built on top of the C++ functions
+             above to do the work.
+
+          Note: it does not make sense for all of the $vm functions to have a C++
+          counterpart for lldb debugging.  For example, the $vm.dfgTrue() function is
+          only useful for JS code, and works via the DFG intrinsics mechanism.
+          When doing debugging via lldb, the optimization level of the currently
+          executing JS function can be gotten by dumping the current CallFrame instead.
+
+        (JSC::currentThreadOwnsJSLock):
+        (JSC::ensureCurrentThreadOwnsJSLock):
+        (JSC::JSDollarVMPrototype::addFunction):
+        (JSC::functionCrash): - $vm.crash()
+        (JSC::functionDFGTrue): - $vm.dfgTrue()
+        (JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
+        (JSC::CallerFrameJITTypeFunctor::operator()):
+        (JSC::CallerFrameJITTypeFunctor::jitType):
+        (JSC::functionLLintTrue): - $vm.llintTrue()
+        (JSC::functionJITTrue): - $vm.jitTrue()
+        (JSC::gc):
+        (JSC::functionGC): - $vm.gc()
+        (JSC::edenGC):
+        (JSC::functionEdenGC): - $vm.edenGC()
+        (JSC::isValidCodeBlock):
+        (JSC::codeBlockForFrame):
+        (JSC::functionCodeBlockForFrame): - $vm.codeBlockForFrame(frameNumber)
+        (JSC::codeBlockFromArg):
+        (JSC::functionPrintSourceFor): - $vm.printSourceFor(codeBlock)
+        (JSC::functionPrintByteCodeFor): - $vm.printBytecodeFor(codeBlock)
+        (JSC::functionPrint): - $vm.print(str)
+        (JSC::PrintFrameFunctor::PrintFrameFunctor):
+        (JSC::PrintFrameFunctor::operator()):
+        (JSC::printCallFrame):
+        (JSC::printStack):
+        (JSC::functionPrintCallFrame): - $vm.printCallFrame()
+        (JSC::functionPrintStack): - $vm.printStack()
+        (JSC::printValue):
+        (JSC::functionPrintValue): - $vm.printValue()
+        (JSC::JSDollarVMPrototype::finishCreation):
+        * tools/JSDollarVMPrototype.h: Added.
+        (JSC::JSDollarVMPrototype::create):
+        (JSC::JSDollarVMPrototype::createStructure):
+        (JSC::JSDollarVMPrototype::JSDollarVMPrototype):
+
 2015-04-16  Geoffrey Garen  <ggaren@apple.com>
 
         Speculative fix after r182915
index c2eab59..ff7a8e1 100644 (file)
     <ClCompile Include="..\tools\CodeProfile.cpp" />
     <ClCompile Include="..\tools\CodeProfiling.cpp" />
     <ClCompile Include="..\tools\FunctionOverrides.cpp" />
+    <ClCompile Include="..\tools\JSDollarVM.cpp" />
+    <ClCompile Include="..\tools\JSDollarVMPrototype.cpp" />
     <ClCompile Include="..\yarr\RegularExpression.cpp" />
     <ClCompile Include="..\yarr\YarrCanonicalizeUCS2.cpp" />
     <ClCompile Include="..\yarr\YarrInterpreter.cpp" />
     <ClInclude Include="..\tools\CodeProfile.h" />
     <ClInclude Include="..\tools\CodeProfiling.h" />
     <ClInclude Include="..\tools\FunctionOverrides.h" />
+    <ClInclude Include="..\tools\JSDollarVM.h" />
+    <ClInclude Include="..\tools\JSDollarVMPrototype.h" />
     <ClInclude Include="..\tools\ProfileTreeNode.h" />
     <ClInclude Include="..\tools\TieredMMapArray.h" />
     <ClInclude Include="..\yarr\RegularExpression.h" />
index ba6e455..a86893e 100644 (file)
     <ClCompile Include="..\tools\FunctionOverrides.cpp">
       <Filter>tools</Filter>
     </ClCompile>
+    <ClCompile Include="..\tools\JSDollarVM.cpp">
+      <Filter>tools</Filter>
+    </ClCompile>
+    <ClCompile Include="..\tools\JSDollarVMPrototype.cpp">
+      <Filter>tools</Filter>
+    </ClCompile>
     <ClCompile Include="..\yarr\RegularExpression.cpp">
       <Filter>yarr</Filter>
     </ClCompile>
     <ClInclude Include="..\tools\FunctionOverrides.h">
       <Filter>tools</Filter>
     </ClInclude>
+    <ClInclude Include="..\tools\JSDollarVM.h">
+      <Filter>tools</Filter>
+    </ClInclude>
+    <ClInclude Include="..\tools\JSDollarVMPrototype.h">
+      <Filter>tools</Filter>
+    </ClInclude>
     <ClInclude Include="..\tools\ProfileTreeNode.h">
       <Filter>tools</Filter>
     </ClInclude>
index 715913b..ba9be0f 100644 (file)
                FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */; };
                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */; };
+               FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */; };
+               FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE384EE71ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */; };
+               FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */; };
                FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */; };
                FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
                FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionOverrides.cpp; sourceTree = "<group>"; };
                FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionOverrides.h; sourceTree = "<group>"; };
+               FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVM.cpp; sourceTree = "<group>"; };
+               FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVM.h; sourceTree = "<group>"; };
+               FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVMPrototype.cpp; sourceTree = "<group>"; };
+               FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVMPrototype.h; sourceTree = "<group>"; };
                FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMEntryScope.cpp; sourceTree = "<group>"; };
                FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; };
                FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapVerifier.cpp; sourceTree = "<group>"; };
                                8603CEF314C7546400AE59E3 /* CodeProfiling.h */,
                                FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */,
                                FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */,
+                               FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */,
+                               FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */,
+                               FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */,
+                               FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */,
                                86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */,
                                86B5826A14D35D5100A9C306 /* TieredMMapArray.h */,
                        );
                                A5EA70EC19F5B3EA0098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py in Headers */,
                                C4F4B6F31A05C944005CAB76 /* cpp_generator_templates.py in Headers */,
                                A5EF9B151A1D43FA00702E90 /* generate_cpp_backend_dispatcher_implementation.py in Headers */,
+                               FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */,
+                               FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */,
                                6AD2CB4D19B9140100065719 /* DebuggerEvalEnabler.h in Headers */,
                                658D3A5619638268003C45D6 /* VMEntryRecord.h in Headers */,
                                A5EF9B161A1D440000702E90 /* generate_cpp_frontend_dispatcher_header.py in Headers */,
                                0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */,
                                0FBE0F7216C1DB030082C5E8 /* DFGCPSRethreadingPhase.cpp in Sources */,
                                A7D89CF517A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp in Sources */,
+                               FE384EE71ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp in Sources */,
                                0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */,
                                0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */,
                                0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */,
                                0F2B66EB17B6B5AB00A7AE3F /* JSDataView.cpp in Sources */,
                                0F2B66ED17B6B5AB00A7AE3F /* JSDataViewPrototype.cpp in Sources */,
                                0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */,
+                               FE384EE51ADDB7AD0055DE2C /* JSDollarVM.cpp in Sources */,
                                978801401471AD920041B016 /* JSDateMath.cpp in Sources */,
                                0FE050171AA9091100D33B33 /* DirectArguments.cpp in Sources */,
                                140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */,
index d511663..1d82387 100644 (file)
@@ -531,7 +531,9 @@ void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, con
             if (target)
                 out.printf(" jit(%p, exec %p)", target, target->executable());
         }
-        out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")");
+        
+        if (jitType() != JITCode::FTLJIT)
+            out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")");
 #else
         UNUSED_PARAM(map);
 #endif
index 36ec22d..260cdd9 100644 (file)
@@ -992,12 +992,12 @@ void Heap::addToRememberedSet(const JSCell* cell)
     m_slotVisitor.unconditionallyAppend(const_cast<JSCell*>(cell));
 }
 
-void Heap::collectAllGarbage()
+void Heap::collectAndSweep(HeapOperation collectionType)
 {
     if (!m_isSafeToCollect)
         return;
 
-    collect(FullCollection);
+    collect(collectionType);
 
     SamplingRegion samplingRegion("Garbage Collection: Sweeping");
 
index 22b0fc7..45bdf6f 100644 (file)
@@ -154,7 +154,8 @@ public:
     void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
     bool isSafeToCollect() const { return m_isSafeToCollect; }
 
-    JS_EXPORT_PRIVATE void collectAllGarbage();
+    void collectAllGarbage() { collectAndSweep(FullCollection); }
+    JS_EXPORT_PRIVATE void collectAndSweep(HeapOperation collectionType = AnyCollection);
     bool shouldCollect();
     JS_EXPORT_PRIVATE void collect(HeapOperation collectionType = AnyCollection);
     bool collectIfNecessaryOrDefer(); // Returns true if it did collect.
index 6f03f66..d4f85ba 100644 (file)
@@ -313,34 +313,23 @@ void StackVisitor::Frame::setToEnd()
 #endif
 }
 
-#ifndef NDEBUG
-
-static const char* jitTypeName(JITCode::JITType jitType)
-{
-    switch (jitType) {
-    case JITCode::None: return "None";
-    case JITCode::HostCallThunk: return "HostCallThunk";
-    case JITCode::InterpreterThunk: return "InterpreterThunk";
-    case JITCode::BaselineJIT: return "BaselineJIT";
-    case JITCode::DFGJIT: return "DFGJIT";
-    case JITCode::FTLJIT: return "FTLJIT";
-    }
-    return "<unknown>";
-}
-
 static void printIndents(int levels)
 {
     while (levels--)
         dataLogFString("   ");
 }
 
-static void printif(int indentLevels, const char* format, ...)
+template<typename... Types>
+void log(unsigned indent, const Types&... values)
 {
-    va_list argList;
-    va_start(argList, format);
+    printIndents(indent);
+    dataLog(values...);
+}
 
-    if (indentLevels)
-        printIndents(indentLevels);
+template<typename... Types>
+void logF(unsigned indent, const char* format, const Types&... values)
+{
+    printIndents(indent);
 
 #if COMPILER(CLANG) || COMPILER(GCC)
 #pragma GCC diagnostic push
@@ -348,121 +337,80 @@ static void printif(int indentLevels, const char* format, ...)
 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
 #endif
 
-    WTF::dataLogFV(format, argList);
+    dataLogF(format, values...);
 
 #if COMPILER(CLANG) || COMPILER(GCC)
 #pragma GCC diagnostic pop
 #endif
-
-    va_end(argList);
 }
 
-void StackVisitor::Frame::print(int indentLevel)
+void StackVisitor::Frame::print(int indent)
 {
-    int i = indentLevel;
-
     if (!this->callFrame()) {
-        printif(i, "frame 0x0\n");
+        log(indent, "frame 0x0\n");
         return;
     }
 
     CodeBlock* codeBlock = this->codeBlock();
-    printif(i, "frame %p {\n", this->callFrame());
+    logF(indent, "frame %p {\n", this->callFrame());
 
-    CallFrame* callFrame = m_callFrame;
-    CallFrame* callerFrame = this->callerFrame();
-    void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
+    {
+        indent++;
 
-    printif(i, "   name '%s'\n", functionName().utf8().data());
-    printif(i, "   sourceURL '%s'\n", sourceURL().utf8().data());
+        CallFrame* callFrame = m_callFrame;
+        CallFrame* callerFrame = this->callerFrame();
+        void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
+
+        log(indent, "name: ", functionName(), "\n");
+        log(indent, "sourceURL: ", sourceURL(), "\n");
 
 #if ENABLE(DFG_JIT)
-    printif(i, "   isInlinedFrame %d\n", isInlinedFrame());
-    if (isInlinedFrame())
-        printif(i, "   InlineCallFrame %p\n", m_inlineCallFrame);
+        log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
+        if (isInlinedFrame())
+            logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
 #endif
 
-    printif(i, "   callee %p\n", callee());
-    printif(i, "   returnPC %p\n", returnPC);
-    printif(i, "   callerFrame %p\n", callerFrame);
-    unsigned locationRawBits = callFrame->locationAsRawBits();
-    printif(i, "   rawLocationBits %u 0x%x\n", locationRawBits, locationRawBits);
-    printif(i, "   codeBlock %p\n", codeBlock);
-    if (codeBlock) {
-        JITCode::JITType jitType = codeBlock->jitType();
-        if (callFrame->hasLocationAsBytecodeOffset()) {
-            unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
-            printif(i, "      bytecodeOffset %u %p / %zu\n", bytecodeOffset, reinterpret_cast<void*>(bytecodeOffset), codeBlock->instructions().size());
+        logF(indent, "callee: %p\n", callee());
+        logF(indent, "returnPC: %p\n", returnPC);
+        logF(indent, "callerFrame: %p\n", callerFrame);
+        unsigned locationRawBits = callFrame->locationAsRawBits();
+        logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
+        logF(indent, "codeBlock: %p ", codeBlock);
+        if (codeBlock)
+            dataLog(*codeBlock);
+        dataLog("\n");
+        if (codeBlock && !isInlinedFrame()) {
+            indent++;
+
+            if (callFrame->hasLocationAsBytecodeOffset()) {
+                unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
+                log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
 #if ENABLE(DFG_JIT)
-        } else {
-            unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
-            printif(i, "      codeOriginIdex %u %p / %zu\n", codeOriginIndex, reinterpret_cast<void*>(codeOriginIndex), codeBlock->codeOrigins().size());
+            } else {
+                log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
+                if (codeBlock->hasCodeOrigins()) {
+                    unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
+                    log(indent, "codeOriginIndex: ", codeOriginIndex, " of ", codeBlock->codeOrigins().size(), "\n");
+
+                    JITCode::JITType jitType = codeBlock->jitType();
+                    if (jitType != JITCode::FTLJIT) {
+                        JITCode* jitCode = codeBlock->jitCode().get();
+                        logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
+                    }
+                }
 #endif
+            }
+            unsigned line = 0;
+            unsigned column = 0;
+            computeLineAndColumn(line, column);
+            log(indent, "line: ", line, "\n");
+            log(indent, "column: ", column, "\n");
+
+            indent--;
         }
-        unsigned line = 0;
-        unsigned column = 0;
-        computeLineAndColumn(line, column);
-        printif(i, "      line %d\n", line);
-        printif(i, "      column %d\n", column);
-        printif(i, "      jitType %d <%s> isOptimizingJIT %d\n", jitType, jitTypeName(jitType), JITCode::isOptimizingJIT(jitType));
-#if ENABLE(DFG_JIT)
-        printif(i, "      hasCodeOrigins %d\n", codeBlock->hasCodeOrigins());
-        if (codeBlock->hasCodeOrigins()) {
-            JITCode* jitCode = codeBlock->jitCode().get();
-            printif(i, "         jitCode %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
-        }
-#endif
+        indent--;
     }
-    printif(i, "}\n");
+    log(indent, "}\n");
 }
 
-#endif // NDEBUG
-
 } // namespace JSC
-
-#ifndef NDEBUG
-using JSC::StackVisitor;
-
-// For debugging use
-JS_EXPORT_PRIVATE void debugPrintCallFrame(JSC::CallFrame*);
-JS_EXPORT_PRIVATE void debugPrintStack(JSC::CallFrame* topCallFrame);
-
-class DebugPrintFrameFunctor {
-public:
-    enum Action {
-        PrintOne,
-        PrintAll
-    };
-
-    DebugPrintFrameFunctor(Action action)
-        : m_action(action)
-    {
-    }
-
-    StackVisitor::Status operator()(StackVisitor& visitor)
-    {
-        visitor->print(2);
-        return m_action == PrintAll ? StackVisitor::Continue : StackVisitor::Done;
-    }
-
-private:
-    Action m_action;
-};
-
-void debugPrintCallFrame(JSC::CallFrame* callFrame)
-{
-    if (!callFrame)
-        return;
-    DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintOne);
-    callFrame->iterate(functor);
-}
-
-void debugPrintStack(JSC::CallFrame* topCallFrame)
-{
-    if (!topCallFrame)
-        return;
-    DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintAll);
-    topCallFrame->iterate(functor);
-}
-
-#endif // !NDEBUG
index bda84d1..0036a78 100644 (file)
@@ -82,9 +82,7 @@ public:
         VMEntryFrame* vmEntryFrame() const { return m_VMEntryFrame; }
         CallFrame* callFrame() const { return m_callFrame; }
         
-#ifndef NDEBUG
         JS_EXPORT_PRIVATE void print(int indentLevel);
-#endif
 
     private:
         Frame() { }
index 23df3a4..817fade 100644 (file)
@@ -67,6 +67,8 @@
 #include "JSConsole.h"
 #include "JSDataView.h"
 #include "JSDataViewPrototype.h"
+#include "JSDollarVM.h"
+#include "JSDollarVMPrototype.h"
 #include "JSFunction.h"
 #include "JSFunctionNameScope.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
@@ -450,6 +452,13 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
     JSConsole* consoleObject = JSConsole::create(vm, m_consoleStructure.get());
     putDirectWithoutTransition(vm, Identifier::fromString(exec, "console"), consoleObject, DontEnum);
 
+    if (UNLIKELY(Options::enableDollarVM())) {
+        JSDollarVMPrototype* dollarVMPrototype = JSDollarVMPrototype::create(vm, this, JSDollarVMPrototype::createStructure(vm, this, m_objectPrototype.get()));
+        m_dollarVMStructure.set(vm, this, JSDollarVM::createStructure(vm, this, dollarVMPrototype));
+        JSDollarVM* dollarVM = JSDollarVM::create(vm, m_dollarVMStructure.get());
+        putDirectWithoutTransition(vm, Identifier::fromString(exec, "$vm"), dollarVM, DontEnum);
+    }
+
     resetPrototype(vm, prototype());
 }
 
@@ -729,6 +738,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_regExpMatchesArrayStructure);
     visitor.append(&thisObject->m_regExpStructure);
     visitor.append(&thisObject->m_consoleStructure);
+    visitor.append(&thisObject->m_dollarVMStructure);
     visitor.append(&thisObject->m_internalFunctionStructure);
 
 #if ENABLE(PROMISES)
index 513dde7..cdb4b40 100644 (file)
@@ -231,6 +231,7 @@ protected:
     WriteBarrier<Structure> m_regExpMatchesArrayStructure;
     WriteBarrier<Structure> m_regExpStructure;
     WriteBarrier<Structure> m_consoleStructure;
+    WriteBarrier<Structure> m_dollarVMStructure;
     WriteBarrier<Structure> m_internalFunctionStructure;
     
     WriteBarrier<Structure> m_iteratorResultStructure;
index 179318a..0b9a78b 100644 (file)
@@ -306,6 +306,7 @@ typedef const char* optionString;
     v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, nullptr) \
     v(bool, verboseExecutableAllocationFuzz, false, nullptr) \
     \
+    v(bool, enableDollarVM, false, "installs the $vm debugging tool in global objects") \
     v(optionString, functionOverrides, nullptr, "file with debugging overrides for function bodies") \
 
 class Options {
diff --git a/Source/JavaScriptCore/tools/JSDollarVM.cpp b/Source/JavaScriptCore/tools/JSDollarVM.cpp
new file mode 100644 (file)
index 0000000..ee5c3d1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * 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. ``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
+ * 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 "JSDollarVM.h"
+
+#include "JSCJSValueInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVM) };
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVM.h b/Source/JavaScriptCore/tools/JSDollarVM.h
new file mode 100644 (file)
index 0000000..6b5be03
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * 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. ``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
+ * 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.
+ */
+
+#ifndef JSDollarVM_h
+#define JSDollarVM_h
+
+#include "JSObject.h"
+
+namespace JSC {
+    
+class JSDollarVM : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+    
+    DECLARE_EXPORT_INFO;
+    
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+    
+    static JSDollarVM* create(VM& vm, Structure* structure)
+    {
+        JSDollarVM* instance = new (NotNull, allocateCell<JSDollarVM>(vm.heap)) JSDollarVM(vm, structure);
+        instance->finishCreation(vm);
+        return instance;
+    }
+    
+private:
+    JSDollarVM(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+};
+
+} // namespace JSC
+
+#endif // JSDollarVM_h
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp
new file mode 100644 (file)
index 0000000..d8427de
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * 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. ``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
+ * 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 "JSDollarVMPrototype.h"
+
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "StackVisitor.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+// The following are exported because they are designed to be callable from
+// lldb. The JS versions in JSDollarVMPrototype are implemented on top of these.
+
+JS_EXPORT_PRIVATE bool currentThreadOwnsJSLock(ExecState*);
+JS_EXPORT_PRIVATE void gc(ExecState*);
+JS_EXPORT_PRIVATE void edenGC(ExecState*);
+JS_EXPORT_PRIVATE bool isValidCodeBlock(ExecState*, CodeBlock*);
+JS_EXPORT_PRIVATE CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber);
+JS_EXPORT_PRIVATE void printCallFrame(CallFrame*);
+JS_EXPORT_PRIVATE void printStack(CallFrame* topCallFrame);
+JS_EXPORT_PRIVATE void printValue(JSValue);
+
+bool currentThreadOwnsJSLock(ExecState* exec)
+{
+    return exec->vm().apiLock().currentThreadIsHoldingLock();
+}
+
+static bool ensureCurrentThreadOwnsJSLock(ExecState* exec)
+{
+    if (currentThreadOwnsJSLock(exec))
+        return true;
+    dataLog("ERROR: current thread does not own the JSLock\n");
+    return false;
+}
+
+
+const ClassInfo JSDollarVMPrototype::s_info = { "DollarVMPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVMPrototype) };
+
+
+void JSDollarVMPrototype::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments)
+{
+    Identifier identifier = Identifier::fromString(&vm, name);
+    putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function));
+}
+
+static NO_RETURN EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*)
+{
+    CRASH();
+}
+
+static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*)
+{
+    return JSValue::encode(jsBoolean(false));
+}
+
+class CallerFrameJITTypeFunctor {
+public:
+    CallerFrameJITTypeFunctor()
+        : m_currentFrame(0)
+        , m_jitType(JITCode::None)
+    {
+    }
+
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        if (m_currentFrame++ > 1) {
+            m_jitType = visitor->codeBlock()->jitType();
+            return StackVisitor::Done;
+        }
+        return StackVisitor::Continue;
+    }
+    
+    JITCode::JITType jitType() { return m_jitType; }
+
+private:
+    unsigned m_currentFrame;
+    JITCode::JITType m_jitType;
+};
+
+static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec)
+{
+    if (!exec)
+        return JSValue::encode(jsUndefined());
+    CallerFrameJITTypeFunctor functor;
+    exec->iterate(functor);
+    return JSValue::encode(jsBoolean(functor.jitType() == JITCode::InterpreterThunk));
+}
+
+static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec)
+{
+    if (!exec)
+        return JSValue::encode(jsUndefined());
+    CallerFrameJITTypeFunctor functor;
+    exec->iterate(functor);
+    return JSValue::encode(jsBoolean(functor.jitType() == JITCode::BaselineJIT));
+}
+
+void gc(ExecState* exec)
+{
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return;
+    exec->heap()->collectAllGarbage();
+}
+    
+static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
+{
+    gc(exec);
+    return JSValue::encode(jsUndefined());
+}
+
+void edenGC(ExecState* exec)
+{
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return;
+    exec->heap()->collectAndSweep(EdenCollection);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
+{
+    edenGC(exec);
+    return JSValue::encode(jsUndefined());
+}
+
+bool isValidCodeBlock(ExecState* exec, CodeBlock* candidate)
+{
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return false;
+    
+    struct CodeBlockValidationFunctor {
+        CodeBlockValidationFunctor(CodeBlock* candidate)
+            : candidate(candidate)
+        {
+        }
+        
+        bool operator()(CodeBlock* codeBlock)
+        {
+            if (codeBlock == candidate)
+                found = true;
+            return found;
+        }
+        
+        CodeBlock* candidate;
+        bool found { false };
+    };
+    
+    VM& vm = exec->vm();
+    CodeBlockValidationFunctor functor(candidate);
+    vm.heap.forEachCodeBlock(functor);
+    return functor.found;
+}
+
+CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber)
+{
+    if (!ensureCurrentThreadOwnsJSLock(topCallFrame))
+        return nullptr;
+    
+    if (!topCallFrame)
+        return nullptr;
+    
+    struct FetchCodeBlockFunctor {
+    public:
+        FetchCodeBlockFunctor(unsigned targetFrameNumber)
+            : targetFrame(targetFrameNumber)
+        {
+        }
+        
+        StackVisitor::Status operator()(StackVisitor& visitor)
+        {
+            currentFrame++;
+            if (currentFrame == targetFrame) {
+                codeBlock = visitor->codeBlock();
+                return StackVisitor::Done;
+            }
+            return StackVisitor::Continue;
+        }
+        
+        unsigned targetFrame;
+        unsigned currentFrame { 0 };
+        CodeBlock* codeBlock { nullptr };
+    };
+    
+    FetchCodeBlockFunctor functor(frameNumber);
+    topCallFrame->iterate(functor);
+    return functor.codeBlock;
+}
+
+static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return JSValue::encode(jsUndefined());
+
+    JSValue value = exec->uncheckedArgument(0);
+    if (!value.isUInt32())
+        return JSValue::encode(jsUndefined());
+
+    // We need to inc the frame number because the caller would consider
+    // its own frame as frame 0. Hence, we need discount the frame for this
+    // function.
+    unsigned frameNumber = value.asUInt32() + 1;
+    CodeBlock* codeBlock = codeBlockForFrame(exec, frameNumber);
+    return JSValue::encode(JSValue(bitwise_cast<double>(reinterpret_cast<uint64_t>(codeBlock))));
+}
+
+static CodeBlock* codeBlockFromArg(ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return nullptr;
+
+    JSValue value = exec->uncheckedArgument(0);
+    if (!value.isDouble()) {
+        dataLog("Invalid codeBlock: ", value, "\n");
+        return nullptr;
+    }
+
+    CodeBlock* codeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
+    if (isValidCodeBlock(exec, codeBlock))
+        return codeBlock;
+
+    dataLogF("Invalid codeBlock: %p ", codeBlock);
+    dataLog(value, "\n");
+    return nullptr;
+    
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintSourceFor(ExecState* exec)
+{
+    CodeBlock* codeBlock = codeBlockFromArg(exec);
+    if (codeBlock)
+        codeBlock->dumpSource();
+    return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintByteCodeFor(ExecState* exec)
+{
+    CodeBlock* codeBlock = codeBlockFromArg(exec);
+    if (codeBlock)
+        codeBlock->dumpBytecode();
+    return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
+{
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        if (i)
+            dataLog(" ");
+        dataLog(exec->uncheckedArgument(i).toString(exec)->value(exec));
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+class PrintFrameFunctor {
+public:
+    enum Action {
+        PrintOne,
+        PrintAll
+    };
+    
+    PrintFrameFunctor(Action action, unsigned framesToSkip)
+        : m_action(action)
+        , m_framesToSkip(framesToSkip)
+    {
+    }
+    
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        m_currentFrame++;
+        if (m_currentFrame > m_framesToSkip)
+            visitor->print(2);
+        
+        if (m_action == PrintOne && m_currentFrame > m_framesToSkip)
+            return StackVisitor::Done;
+        return StackVisitor::Continue;
+    }
+    
+private:
+    Action m_action;
+    unsigned m_framesToSkip;
+    unsigned m_currentFrame { 0 };
+};
+
+static void printCallFrame(CallFrame* callFrame, unsigned framesToSkip)
+{
+    if (!ensureCurrentThreadOwnsJSLock(callFrame))
+        return;
+    PrintFrameFunctor functor(PrintFrameFunctor::PrintOne, framesToSkip);
+    callFrame->iterate(functor);
+}
+
+void printCallFrame(CallFrame* callFrame)
+{
+    printCallFrame(callFrame, 0);
+}
+
+static void printStack(CallFrame* topCallFrame, unsigned framesToSkip)
+{
+    if (!ensureCurrentThreadOwnsJSLock(topCallFrame))
+        return;
+    if (!topCallFrame)
+        return;
+    PrintFrameFunctor functor(PrintFrameFunctor::PrintAll, framesToSkip);
+    topCallFrame->iterate(functor);
+}
+
+void printStack(CallFrame* topCallFrame)
+{
+    printStack(topCallFrame, 0);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintCallFrame(ExecState* exec)
+{
+    // When the callers call this function, they are expecting to print their
+    // own frame. So skip 1 for this frame.
+    printCallFrame(exec, 1);
+    return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintStack(ExecState* exec)
+{
+    // When the callers call this function, they are expecting to print the
+    // stack starting their own frame. So skip 1 for this frame.
+    printStack(exec, 1);
+    return JSValue::encode(jsUndefined());
+}
+
+void printValue(JSValue value)
+{
+    dataLog(value);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionPrintValue(ExecState* exec)
+{
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        if (i)
+            dataLog(" ");
+        dataLog(exec->uncheckedArgument(i));
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+void JSDollarVMPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+    Base::finishCreation(vm);
+    
+    addFunction(vm, globalObject, "crash", functionCrash, 0);
+    
+    putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "dfgTrue"), 0, functionDFGTrue, DFGTrueIntrinsic, DontEnum | JSC::Function);
+    
+    addFunction(vm, globalObject, "llintTrue", functionLLintTrue, 0);
+    addFunction(vm, globalObject, "jitTrue", functionJITTrue, 0);
+    
+    addFunction(vm, globalObject, "gc", functionGC, 0);
+    addFunction(vm, globalObject, "edenGC", functionEdenGC, 0);
+    
+    addFunction(vm, globalObject, "codeBlockForFrame", functionCodeBlockForFrame, 1);
+    addFunction(vm, globalObject, "printSourceFor", functionPrintSourceFor, 1);
+    addFunction(vm, globalObject, "printByteCodeFor", functionPrintByteCodeFor, 1);
+    
+    addFunction(vm, globalObject, "print", functionPrint, 1);
+    addFunction(vm, globalObject, "printCallFrame", functionPrintCallFrame, 0);
+    addFunction(vm, globalObject, "printStack", functionPrintStack, 0);
+
+    addFunction(vm, globalObject, "printValue", functionPrintValue, 1);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.h b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h
new file mode 100644 (file)
index 0000000..b1bef84
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * 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. ``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
+ * 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.
+ */
+
+#ifndef JSDollarVMPrototype_h
+#define JSDollarVMPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSDollarVMPrototype : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+
+    DECLARE_INFO;
+
+    static JSDollarVMPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+    {
+        JSDollarVMPrototype* prototype = new (NotNull, allocateCell<JSDollarVMPrototype>(vm.heap)) JSDollarVMPrototype(vm, structure);
+        prototype->finishCreation(vm, globalObject);
+        return prototype;
+    }
+    
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+private:
+    JSDollarVMPrototype(VM& vm, Structure* structure)
+        : Base(vm, structure)
+    {
+    }
+
+    void finishCreation(VM&, JSGlobalObject*);
+    void addFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments);
+};
+
+} // namespace JSC
+
+#endif // JSDollarVMPrototype_h