Remove JSDollarVMPrototype.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Nov 2017 21:16:24 +0000 (21:16 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 14 Nov 2017 21:16:24 +0000 (21:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179685

Reviewed by Saam Barati.

1. Move the JSDollarVMPrototype C++ utility functions into VMInspector.cpp.

   This allows us to call these functions during lldb debugging sessions using
   VMInspector::foo() instead of JSDollarVMPrototype::foo().  It makes sense that
   VMInspector provides VM debugging utility methods.  It doesn't make sense to
   have a JSDollarVMPrototype object provide these methods.

   Plus, it's shorter to type VMInspector than JSDollarVMPrototype.

2. Move the JSDollarVMPrototype JS functions into JSDollarVM.cpp.

   JSDollarVM is a special object used only for debugging purposes.  There's no
   gain in requiring its methods to be stored in a prototype object other than to
   conform to typical JS convention.  We can remove this complexity.

* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* tools/JSDollarVM.cpp:
(JSC::JSDollarVM::addFunction):
(JSC::functionCrash):
(JSC::functionDFGTrue):
(JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
(JSC::CallerFrameJITTypeFunctor::operator() const):
(JSC::CallerFrameJITTypeFunctor::jitType):
(JSC::functionLLintTrue):
(JSC::functionJITTrue):
(JSC::functionGC):
(JSC::functionEdenGC):
(JSC::functionCodeBlockForFrame):
(JSC::codeBlockFromArg):
(JSC::functionCodeBlockFor):
(JSC::functionPrintSourceFor):
(JSC::functionPrintBytecodeFor):
(JSC::functionPrint):
(JSC::functionPrintCallFrame):
(JSC::functionPrintStack):
(JSC::functionValue):
(JSC::functionGetPID):
(JSC::JSDollarVM::finishCreation):
* tools/JSDollarVM.h:
(JSC::JSDollarVM::create):
* tools/JSDollarVMPrototype.cpp: Removed.
* tools/JSDollarVMPrototype.h: Removed.
* tools/VMInspector.cpp:
(JSC::VMInspector::currentThreadOwnsJSLock):
(JSC::ensureCurrentThreadOwnsJSLock):
(JSC::VMInspector::gc):
(JSC::VMInspector::edenGC):
(JSC::VMInspector::isInHeap):
(JSC::CellAddressCheckFunctor::CellAddressCheckFunctor):
(JSC::CellAddressCheckFunctor::operator() const):
(JSC::VMInspector::isValidCell):
(JSC::VMInspector::isValidCodeBlock):
(JSC::VMInspector::codeBlockForFrame):
(JSC::PrintFrameFunctor::PrintFrameFunctor):
(JSC::PrintFrameFunctor::operator() const):
(JSC::VMInspector::printCallFrame):
(JSC::VMInspector::printStack):
(JSC::VMInspector::printValue):
* tools/VMInspector.h:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/tools/JSDollarVM.cpp
Source/JavaScriptCore/tools/JSDollarVM.h
Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp [deleted file]
Source/JavaScriptCore/tools/JSDollarVMPrototype.h [deleted file]
Source/JavaScriptCore/tools/VMInspector.cpp
Source/JavaScriptCore/tools/VMInspector.h

index 0bc41d6..4bb37b4 100644 (file)
@@ -1,3 +1,73 @@
+2017-11-14  Mark Lam  <mark.lam@apple.com>
+
+        Remove JSDollarVMPrototype.
+        https://bugs.webkit.org/show_bug.cgi?id=179685
+
+        Reviewed by Saam Barati.
+
+        1. Move the JSDollarVMPrototype C++ utility functions into VMInspector.cpp.
+
+           This allows us to call these functions during lldb debugging sessions using
+           VMInspector::foo() instead of JSDollarVMPrototype::foo().  It makes sense that
+           VMInspector provides VM debugging utility methods.  It doesn't make sense to
+           have a JSDollarVMPrototype object provide these methods.
+
+           Plus, it's shorter to type VMInspector than JSDollarVMPrototype.
+
+        2. Move the JSDollarVMPrototype JS functions into JSDollarVM.cpp.
+
+           JSDollarVM is a special object used only for debugging purposes.  There's no
+           gain in requiring its methods to be stored in a prototype object other than to
+           conform to typical JS convention.  We can remove this complexity.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * tools/JSDollarVM.cpp:
+        (JSC::JSDollarVM::addFunction):
+        (JSC::functionCrash):
+        (JSC::functionDFGTrue):
+        (JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
+        (JSC::CallerFrameJITTypeFunctor::operator() const):
+        (JSC::CallerFrameJITTypeFunctor::jitType):
+        (JSC::functionLLintTrue):
+        (JSC::functionJITTrue):
+        (JSC::functionGC):
+        (JSC::functionEdenGC):
+        (JSC::functionCodeBlockForFrame):
+        (JSC::codeBlockFromArg):
+        (JSC::functionCodeBlockFor):
+        (JSC::functionPrintSourceFor):
+        (JSC::functionPrintBytecodeFor):
+        (JSC::functionPrint):
+        (JSC::functionPrintCallFrame):
+        (JSC::functionPrintStack):
+        (JSC::functionValue):
+        (JSC::functionGetPID):
+        (JSC::JSDollarVM::finishCreation):
+        * tools/JSDollarVM.h:
+        (JSC::JSDollarVM::create):
+        * tools/JSDollarVMPrototype.cpp: Removed.
+        * tools/JSDollarVMPrototype.h: Removed.
+        * tools/VMInspector.cpp:
+        (JSC::VMInspector::currentThreadOwnsJSLock):
+        (JSC::ensureCurrentThreadOwnsJSLock):
+        (JSC::VMInspector::gc):
+        (JSC::VMInspector::edenGC):
+        (JSC::VMInspector::isInHeap):
+        (JSC::CellAddressCheckFunctor::CellAddressCheckFunctor):
+        (JSC::CellAddressCheckFunctor::operator() const):
+        (JSC::VMInspector::isValidCell):
+        (JSC::VMInspector::isValidCodeBlock):
+        (JSC::VMInspector::codeBlockForFrame):
+        (JSC::PrintFrameFunctor::PrintFrameFunctor):
+        (JSC::PrintFrameFunctor::operator() const):
+        (JSC::VMInspector::printCallFrame):
+        (JSC::VMInspector::printStack):
+        (JSC::VMInspector::printValue):
+        * tools/VMInspector.h:
+
 2017-11-14  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Add a ServiceWorker domain to get information about an inspected ServiceWorker
index c570ef6..a9c4a99 100644 (file)
                FE318FE01CAC982F00DFCC54 /* ECMAScriptSpecInternalFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */; };
                FE3422121D6B81C30032BE88 /* ThrowScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3422111D6B818C0032BE88 /* ThrowScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE3A06A61C10B72D00390FDD /* JITBitOrGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06A41C10B70800390FDD /* JITBitOrGenerator.h */; };
                FE3A06A81C10BC8100390FDD /* JITBitBinaryOpGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06A71C10BC7400390FDD /* JITBitBinaryOpGenerator.h */; };
                FE3A06B21C10CB8900390FDD /* JITBitAndGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06AE1C10CB6F00390FDD /* JITBitAndGenerator.h */; };
                530A66B51FA3E77D0026A545 /* UnifiedSource5-mm.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "UnifiedSource5-mm.mm"; sourceTree = "<group>"; };
                530A66B61FA3E77D0026A545 /* UnifiedSource142.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource142.cpp; sourceTree = "<group>"; };
                530A66B71FA3E77D0026A545 /* UnifiedSource143.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource143.cpp; sourceTree = "<group>"; };
-                530A66B81FA3E77E0026A545 /* UnifiedSource4-mm.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "UnifiedSource4-mm.mm"; sourceTree = "<group>"; };
-                530A66CC1FB1346D0026A545 /* SuperSamplerBytecodeScope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuperSamplerBytecodeScope.h; sourceTree = "<group>"; };
-                530FB3011E7A0B6E003C19DD /* WasmWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmWorklist.h; sourceTree = "<group>"; };
+               530A66B81FA3E77E0026A545 /* UnifiedSource4-mm.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "UnifiedSource4-mm.mm"; sourceTree = "<group>"; };
+               530A66CC1FB1346D0026A545 /* SuperSamplerBytecodeScope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuperSamplerBytecodeScope.h; sourceTree = "<group>"; };
+               530FB3011E7A0B6E003C19DD /* WasmWorklist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmWorklist.h; sourceTree = "<group>"; };
                530FB3031E7A1146003C19DD /* WasmWorklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmWorklist.cpp; sourceTree = "<group>"; };
                5311BD481EA581E500525281 /* WasmOMGPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmOMGPlan.cpp; sourceTree = "<group>"; };
                5311BD491EA581E500525281 /* WasmOMGPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmOMGPlan.h; sourceTree = "<group>"; };
                FE3422111D6B818C0032BE88 /* ThrowScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThrowScope.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>"; };
                FE3A06A31C10B70800390FDD /* JITBitOrGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITBitOrGenerator.cpp; sourceTree = "<group>"; };
                FE3A06A41C10B70800390FDD /* JITBitOrGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITBitOrGenerator.h; sourceTree = "<group>"; };
                FE3A06A71C10BC7400390FDD /* JITBitBinaryOpGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITBitBinaryOpGenerator.h; sourceTree = "<group>"; };
                                FE1BD0231E72052F00134BC9 /* HeapVerifier.h */,
                                FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */,
                                FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */,
-                               FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */,
-                               FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */,
                                86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */,
                                FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */,
                                FE3022D11E3D739600BAC493 /* SigillCrashAnalyzer.h */,
                                C2A7F688160432D400F76B98 /* JSDestructibleObject.h in Headers */,
                                0F7DF13C1E2971130095951B /* JSDestructibleObjectSubspace.h in Headers */,
                                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */,
-                               FE384EE81ADDB7AD0055DE2C /* JSDollarVMPrototype.h in Headers */,
                                86E3C614167BABD7006D760A /* JSExport.h in Headers */,
                                A7B4ACAF1484C9CE00B38A36 /* JSExportMacros.h in Headers */,
                                798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */,
index 5fec842..70e4a32 100644 (file)
@@ -932,7 +932,6 @@ tools/FunctionOverrides.cpp
 tools/FunctionWhitelist.cpp
 tools/HeapVerifier.cpp
 tools/JSDollarVM.cpp
-tools/JSDollarVMPrototype.cpp
 tools/SigillCrashAnalyzer.cpp
 tools/VMInspector.cpp
 
index 29c709a..f1825e9 100644 (file)
@@ -85,7 +85,6 @@
 #include "JSDataView.h"
 #include "JSDataViewPrototype.h"
 #include "JSDollarVM.h"
-#include "JSDollarVMPrototype.h"
 #include "JSFunction.h"
 #include "JSGeneratorFunction.h"
 #include "JSGenericTypedArrayViewConstructorInlines.h"
@@ -896,9 +895,8 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
     m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::ThrowTypeErrorFunction)] = m_throwTypeErrorFunction.get();
 
     if (UNLIKELY(Options::useDollarVM())) {
-        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());
+        m_dollarVMStructure.set(vm, this, JSDollarVM::createStructure(vm, this, m_objectPrototype.get()));
+        JSDollarVM* dollarVM = JSDollarVM::create(vm, this, m_dollarVMStructure.get());
 
         GlobalPropertyInfo extraStaticGlobals[] = {
             GlobalPropertyInfo(vm.propertyNames->builtinNames().dollarVMPrivateName(), dollarVM, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
index 3321513..3367997 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "config.h"
 #include "JSDollarVM.h"
 
+#include "CodeBlock.h"
+#include "FunctionCodeBlock.h"
 #include "JSCInlines.h"
+#include "VMInspector.h"
+#include <wtf/DataLog.h>
+#include <wtf/ProcessID.h>
+#include <wtf/StringPrintStream.h>
 
 namespace JSC {
 
 const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVM) };
 
+void JSDollarVM::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));
+}
+
+// Triggers a crash immediately.
+// Usage: $vm.crash()
+static EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*)
+{
+    CRASH();
+    return JSValue::encode(jsUndefined());
+}
+
+// Returns true if the current frame is a DFG frame.
+// Usage: isDFG = $vm.dfgTrue()
+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) const
+    {
+        if (m_currentFrame++ > 1) {
+            m_jitType = visitor->codeBlock()->jitType();
+            return StackVisitor::Done;
+        }
+        return StackVisitor::Continue;
+    }
+    
+    JITCode::JITType jitType() { return m_jitType; }
+
+private:
+    mutable unsigned m_currentFrame;
+    mutable JITCode::JITType m_jitType;
+};
+
+// Returns true if the current frame is a LLInt frame.
+// Usage: isLLInt = $vm.llintTrue()
+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));
+}
+
+// Returns true if the current frame is a baseline JIT frame.
+// Usage: isBaselineJIT = $vm.jitTrue()
+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));
+}
+
+// Runs a full GC synchronously.
+// Usage: $vm.gc()
+static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
+{
+    VMInspector::gc(exec);
+    return JSValue::encode(jsUndefined());
+}
+
+// Runs the edenGC synchronously.
+// Usage: $vm.edenGC()
+static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
+{
+    VMInspector::edenGC(exec);
+    return JSValue::encode(jsUndefined());
+}
+
+// Gets a token for the CodeBlock for a specified frame index.
+// Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame.
+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 = VMInspector::codeBlockForFrame(exec, frameNumber);
+    // Though CodeBlock is a JSCell, it is not safe to return it directly back to JS code
+    // as it is an internal type that the JS code cannot handle. Hence, we first encode the
+    // CodeBlock* as a double token (which is safe for JS code to handle) before returning it.
+    return JSValue::encode(JSValue(bitwise_cast<double>(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(codeBlock)))));
+}
+
+static CodeBlock* codeBlockFromArg(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    if (exec->argumentCount() < 1)
+        return nullptr;
+
+    JSValue value = exec->uncheckedArgument(0);
+    CodeBlock* candidateCodeBlock = nullptr;
+    if (value.isCell()) {
+        JSFunction* func = jsDynamicCast<JSFunction*>(vm, value.asCell());
+        if (func) {
+            if (func->isHostFunction())
+                candidateCodeBlock = nullptr;
+            else
+                candidateCodeBlock = func->jsExecutable()->eitherCodeBlock();
+        }
+    } else if (value.isDouble()) {
+        // If the value is a double, it may be an encoded CodeBlock* that came from
+        // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's
+        // valid below before using.
+        candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
+    }
+
+    if (candidateCodeBlock && VMInspector::isValidCodeBlock(exec, candidateCodeBlock))
+        return candidateCodeBlock;
+
+    if (candidateCodeBlock)
+        dataLog("Invalid codeBlock: ", RawPointer(candidateCodeBlock), " ", value, "\n");
+    else
+        dataLog("Invalid codeBlock: ", value, "\n");
+    return nullptr;
+}
+
+// Usage: print("codeblock = " + $vm.codeBlockFor(functionObj))
+// Usage: print("codeblock = " + $vm.codeBlockFor(codeBlockToken))
+static EncodedJSValue JSC_HOST_CALL functionCodeBlockFor(ExecState* exec)
+{
+    CodeBlock* codeBlock = codeBlockFromArg(exec);
+    WTF::StringPrintStream stream;
+    if (codeBlock) {
+        stream.print(*codeBlock);
+        return JSValue::encode(jsString(exec, stream.toString()));
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+// Usage: $vm.printSourceFor(functionObj)
+// Usage: $vm.printSourceFor(codeBlockToken)
+static EncodedJSValue JSC_HOST_CALL functionPrintSourceFor(ExecState* exec)
+{
+    CodeBlock* codeBlock = codeBlockFromArg(exec);
+    if (codeBlock)
+        codeBlock->dumpSource();
+    return JSValue::encode(jsUndefined());
+}
+
+// Usage: $vm.printBytecodeFor(functionObj)
+// Usage: $vm.printBytecode(codeBlockToken)
+static EncodedJSValue JSC_HOST_CALL functionPrintBytecodeFor(ExecState* exec)
+{
+    CodeBlock* codeBlock = codeBlockFromArg(exec);
+    if (codeBlock)
+        codeBlock->dumpBytecode();
+    return JSValue::encode(jsUndefined());
+}
+
+// Prints a series of comma separate strings without inserting a newline.
+// Usage: $vm.print(str1, str2, str3)
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
+{
+    auto scope = DECLARE_THROW_SCOPE(exec->vm());
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        String argStr = exec->uncheckedArgument(i).toWTFString(exec);
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        dataLog(argStr);
+    }
+    return JSValue::encode(jsUndefined());
+}
+
+// Prints the current CallFrame.
+// Usage: $vm.printCallFrame()
+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.
+    VMInspector::printCallFrame(exec, 1);
+    return JSValue::encode(jsUndefined());
+}
+
+// Prints the JS stack.
+// Usage: $vm.printStack()
+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.
+    VMInspector::printStack(exec, 1);
+    return JSValue::encode(jsUndefined());
+}
+
+// Gets the dataLog dump of a given JS value as a string.
+// Usage: print("value = " + $vm.value(jsValue))
+static EncodedJSValue JSC_HOST_CALL functionValue(ExecState* exec)
+{
+    WTF::StringPrintStream stream;
+    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+        if (i)
+            stream.print(", ");
+        stream.print(exec->uncheckedArgument(i));
+    }
+    
+    return JSValue::encode(jsString(exec, stream.toString()));
+}
+
+// Gets the pid of the current process.
+// Usage: print("pid = " + $vm.getpid())
+static EncodedJSValue JSC_HOST_CALL functionGetPID(ExecState*)
+{
+    return JSValue::encode(jsNumber(getCurrentProcessID()));
+}
+
+void JSDollarVM::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+    Base::finishCreation(vm);
+    
+    addFunction(vm, globalObject, "crash", functionCrash, 0);
+    
+    putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "dfgTrue"), 0, functionDFGTrue, DFGTrueIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    
+    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, "codeBlockFor", functionCodeBlockFor, 1);
+    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, "value", functionValue, 1);
+    addFunction(vm, globalObject, "getpid", functionGetPID, 0);
+}
+
 } // namespace JSC
index 2267577..cfe430f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,11 +39,11 @@ public:
     {
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
-    
-    static JSDollarVM* create(VM& vm, Structure* structure)
+
+    static JSDollarVM* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     {
         JSDollarVM* instance = new (NotNull, allocateCell<JSDollarVM>(vm.heap)) JSDollarVM(vm, structure);
-        instance->finishCreation(vm);
+        instance->finishCreation(vm, globalObject);
         return instance;
     }
     
@@ -52,6 +52,9 @@ private:
         : Base(vm, structure)
     {
     }
+
+    void finishCreation(VM&, JSGlobalObject*);
+    void addFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments);
 };
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp
deleted file mode 100644 (file)
index 6f3801e..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "CodeBlock.h"
-#include "FunctionCodeBlock.h"
-#include "Heap.h"
-#include "HeapIterationScope.h"
-#include "JSCInlines.h"
-#include "JSFunction.h"
-#include "MarkedSpaceInlines.h"
-#include "StackVisitor.h"
-#include <wtf/DataLog.h>
-#include <wtf/ProcessID.h>
-#include <wtf/StringPrintStream.h>
-
-namespace JSC {
-
-const ClassInfo JSDollarVMPrototype::s_info = { "DollarVMPrototype", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMPrototype) };
-    
-    
-bool JSDollarVMPrototype::currentThreadOwnsJSLock(ExecState* exec)
-{
-    return exec->vm().currentThreadIsHoldingAPILock();
-}
-
-static bool ensureCurrentThreadOwnsJSLock(ExecState* exec)
-{
-    if (JSDollarVMPrototype::currentThreadOwnsJSLock(exec))
-        return true;
-    dataLog("ERROR: current thread does not own the JSLock\n");
-    return false;
-}
-
-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 EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*)
-{
-    CRASH();
-    return JSValue::encode(jsUndefined());
-}
-
-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) const
-    {
-        if (m_currentFrame++ > 1) {
-            m_jitType = visitor->codeBlock()->jitType();
-            return StackVisitor::Done;
-        }
-        return StackVisitor::Continue;
-    }
-    
-    JITCode::JITType jitType() { return m_jitType; }
-
-private:
-    mutable unsigned m_currentFrame;
-    mutable 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 JSDollarVMPrototype::gc(ExecState* exec)
-{
-    VM& vm = exec->vm();
-    if (!ensureCurrentThreadOwnsJSLock(exec))
-        return;
-    vm.heap.collectNow(Sync, CollectionScope::Full);
-}
-    
-static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
-{
-    JSDollarVMPrototype::gc(exec);
-    return JSValue::encode(jsUndefined());
-}
-
-void JSDollarVMPrototype::edenGC(ExecState* exec)
-{
-    VM& vm = exec->vm();
-    if (!ensureCurrentThreadOwnsJSLock(exec))
-        return;
-    vm.heap.collectSync(CollectionScope::Eden);
-}
-
-static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
-{
-    JSDollarVMPrototype::edenGC(exec);
-    return JSValue::encode(jsUndefined());
-}
-
-bool JSDollarVMPrototype::isInHeap(Heap* heap, void* ptr)
-{
-    return isInObjectSpace(heap, ptr) || isInStorageSpace(heap, ptr);
-}
-
-bool JSDollarVMPrototype::isInObjectSpace(Heap* heap, void* ptr)
-{
-    MarkedBlock* candidate = MarkedBlock::blockFor(ptr);
-    if (heap->objectSpace().blocks().set().contains(candidate))
-        return true;
-    for (LargeAllocation* allocation : heap->objectSpace().largeAllocations()) {
-        if (allocation->contains(ptr))
-            return true;
-    }
-    return false;
-}
-
-bool JSDollarVMPrototype::isInStorageSpace(Heap*, void*)
-{
-    // FIXME: Do something with this.
-    // https://bugs.webkit.org/show_bug.cgi?id=161753
-    return false;
-}
-
-struct CellAddressCheckFunctor : MarkedBlock::CountFunctor {
-    CellAddressCheckFunctor(JSCell* candidate)
-        : candidate(candidate)
-    {
-    }
-
-    IterationStatus operator()(HeapCell* cell, HeapCell::Kind) const
-    {
-        if (cell == candidate) {
-            found = true;
-            return IterationStatus::Done;
-        }
-        return IterationStatus::Continue;
-    }
-
-    JSCell* candidate;
-    mutable bool found { false };
-};
-
-bool JSDollarVMPrototype::isValidCell(Heap* heap, JSCell* candidate)
-{
-    HeapIterationScope iterationScope(*heap);
-    CellAddressCheckFunctor functor(candidate);
-    heap->objectSpace().forEachLiveCell(iterationScope, functor);
-    return functor.found;
-}
-
-bool JSDollarVMPrototype::isValidCodeBlock(ExecState* exec, CodeBlock* candidate)
-{
-    if (!ensureCurrentThreadOwnsJSLock(exec))
-        return false;
-    
-    struct CodeBlockValidationFunctor {
-        CodeBlockValidationFunctor(CodeBlock* candidate)
-            : candidate(candidate)
-        {
-        }
-        
-        bool operator()(CodeBlock* codeBlock) const
-        {
-            if (codeBlock == candidate)
-                found = true;
-            return found;
-        }
-        
-        CodeBlock* candidate;
-        mutable bool found { false };
-    };
-    
-    VM& vm = exec->vm();
-    CodeBlockValidationFunctor functor(candidate);
-    vm.heap.forEachCodeBlock(functor);
-    return functor.found;
-}
-
-CodeBlock* JSDollarVMPrototype::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) const
-        {
-            currentFrame++;
-            if (currentFrame == targetFrame) {
-                codeBlock = visitor->codeBlock();
-                return StackVisitor::Done;
-            }
-            return StackVisitor::Continue;
-        }
-        
-        unsigned targetFrame;
-        mutable unsigned currentFrame { 0 };
-        mutable 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 = JSDollarVMPrototype::codeBlockForFrame(exec, frameNumber);
-    // Though CodeBlock is a JSCell, it is not safe to return it directly back to JS code
-    // as it is an internal type that the JS code cannot handle. Hence, we first encode the
-    // CodeBlock* as a double token (which is safe for JS code to handle) before returning it.
-    return JSValue::encode(JSValue(bitwise_cast<double>(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(codeBlock)))));
-}
-
-static CodeBlock* codeBlockFromArg(ExecState* exec)
-{
-    VM& vm = exec->vm();
-    if (exec->argumentCount() < 1)
-        return nullptr;
-
-    JSValue value = exec->uncheckedArgument(0);
-    CodeBlock* candidateCodeBlock = nullptr;
-    if (value.isCell()) {
-        JSFunction* func = jsDynamicCast<JSFunction*>(vm, value.asCell());
-        if (func) {
-            if (func->isHostFunction())
-                candidateCodeBlock = nullptr;
-            else
-                candidateCodeBlock = func->jsExecutable()->eitherCodeBlock();
-        }
-    } else if (value.isDouble()) {
-        // If the value is a double, it may be an encoded CodeBlock* that came from
-        // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's
-        // valid below before using.
-        candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
-    }
-
-    if (candidateCodeBlock && JSDollarVMPrototype::isValidCodeBlock(exec, candidateCodeBlock))
-        return candidateCodeBlock;
-
-    if (candidateCodeBlock)
-        dataLog("Invalid codeBlock: ", RawPointer(candidateCodeBlock), " ", value, "\n");
-    else
-        dataLog("Invalid codeBlock: ", value, "\n");
-    return nullptr;
-}
-
-static EncodedJSValue JSC_HOST_CALL functionCodeBlockFor(ExecState* exec)
-{
-    CodeBlock* codeBlock = codeBlockFromArg(exec);
-    WTF::StringPrintStream stream;
-    if (codeBlock) {
-        stream.print(*codeBlock);
-        return JSValue::encode(jsString(exec, stream.toString()));
-    }
-    return JSValue::encode(jsUndefined());
-}
-
-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)
-{
-    auto scope = DECLARE_THROW_SCOPE(exec->vm());
-    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
-        String argStr = exec->uncheckedArgument(i).toWTFString(exec);
-        RETURN_IF_EXCEPTION(scope, encodedJSValue());
-        dataLog(argStr);
-    }
-    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) const
-    {
-        m_currentFrame++;
-        if (m_currentFrame > m_framesToSkip) {
-            visitor->dump(WTF::dataFile(), Indenter(2), [&] (PrintStream& out) {
-                out.print("[", (m_currentFrame - m_framesToSkip - 1), "] ");
-            });
-        }
-        if (m_action == PrintOne && m_currentFrame > m_framesToSkip)
-            return StackVisitor::Done;
-        return StackVisitor::Continue;
-    }
-    
-private:
-    Action m_action;
-    unsigned m_framesToSkip;
-    mutable unsigned m_currentFrame { 0 };
-};
-
-static void printCallFrame(CallFrame* callFrame, unsigned framesToSkip)
-{
-    if (!ensureCurrentThreadOwnsJSLock(callFrame))
-        return;
-    PrintFrameFunctor functor(PrintFrameFunctor::PrintOne, framesToSkip);
-    callFrame->iterate(functor);
-}
-
-void JSDollarVMPrototype::printCallFrame(CallFrame* callFrame)
-{
-    JSC::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 JSDollarVMPrototype::printStack(CallFrame* topCallFrame)
-{
-    JSC::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 JSDollarVMPrototype::printValue(JSValue value)
-{
-    dataLog(value);
-}
-
-static EncodedJSValue JSC_HOST_CALL functionValue(ExecState* exec)
-{
-    WTF::StringPrintStream stream;
-    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
-        if (i)
-            stream.print(", ");
-        stream.print(exec->uncheckedArgument(i));
-    }
-    
-    return JSValue::encode(jsString(exec, stream.toString()));
-}
-
-static EncodedJSValue JSC_HOST_CALL functionGetPID(ExecState*)
-{
-    return JSValue::encode(jsNumber(getCurrentProcessID()));
-}
-
-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, static_cast<unsigned>(PropertyAttribute::DontEnum));
-    
-    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, "codeBlockFor", functionCodeBlockFor, 1);
-    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, "value", functionValue, 1);
-    addFunction(vm, globalObject, "getpid", functionGetPID, 0);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.h b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h
deleted file mode 100644 (file)
index 788e267..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include "JSObject.h"
-
-namespace JSC {
-
-class Heap;
-
-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());
-    }
-
-    // The following are exported because they are designed to be callable from
-    // lldb. The JS versions are implemented on top of these.
-    
-    JS_EXPORT_PRIVATE static bool currentThreadOwnsJSLock(ExecState*);
-    JS_EXPORT_PRIVATE static void gc(ExecState*);
-    JS_EXPORT_PRIVATE static void edenGC(ExecState*);
-    JS_EXPORT_PRIVATE static bool isInHeap(Heap*, void*);
-    JS_EXPORT_PRIVATE static bool isInObjectSpace(Heap*, void*);
-    JS_EXPORT_PRIVATE static bool isInStorageSpace(Heap*, void*);
-    JS_EXPORT_PRIVATE static bool isValidCell(Heap*, JSCell*);
-    JS_EXPORT_PRIVATE static bool isValidCodeBlock(ExecState*, CodeBlock*);
-    JS_EXPORT_PRIVATE static CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber);
-    JS_EXPORT_PRIVATE static void printCallFrame(CallFrame*);
-    JS_EXPORT_PRIVATE static void printStack(CallFrame* topCallFrame);
-    JS_EXPORT_PRIVATE static void printValue(JSValue);
-
-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
index bbaaf6a..888ca77 100644 (file)
 #include "CodeBlock.h"
 #include "CodeBlockSet.h"
 #include "HeapInlines.h"
+#include "HeapIterationScope.h"
 #include "MachineContext.h"
+#include "MarkedSpaceInlines.h"
+#include "StackVisitor.h"
 #include <mutex>
 #include <wtf/Expected.h>
 
@@ -194,4 +197,190 @@ auto VMInspector::codeBlockForMachinePC(const VMInspector::Locker&, void* machin
 #endif
 }
 
+bool VMInspector::currentThreadOwnsJSLock(ExecState* exec)
+{
+    return exec->vm().currentThreadIsHoldingAPILock();
+}
+
+static bool ensureCurrentThreadOwnsJSLock(ExecState* exec)
+{
+    if (VMInspector::currentThreadOwnsJSLock(exec))
+        return true;
+    dataLog("ERROR: current thread does not own the JSLock\n");
+    return false;
+}
+
+void VMInspector::gc(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return;
+    vm.heap.collectNow(Sync, CollectionScope::Full);
+}
+
+void VMInspector::edenGC(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return;
+    vm.heap.collectSync(CollectionScope::Eden);
+}
+
+bool VMInspector::isInHeap(Heap* heap, void* ptr)
+{
+    MarkedBlock* candidate = MarkedBlock::blockFor(ptr);
+    if (heap->objectSpace().blocks().set().contains(candidate))
+        return true;
+    for (LargeAllocation* allocation : heap->objectSpace().largeAllocations()) {
+        if (allocation->contains(ptr))
+            return true;
+    }
+    return false;
+}
+
+struct CellAddressCheckFunctor : MarkedBlock::CountFunctor {
+    CellAddressCheckFunctor(JSCell* candidate)
+        : candidate(candidate)
+    {
+    }
+
+    IterationStatus operator()(HeapCell* cell, HeapCell::Kind) const
+    {
+        if (cell == candidate) {
+            found = true;
+            return IterationStatus::Done;
+        }
+        return IterationStatus::Continue;
+    }
+
+    JSCell* candidate;
+    mutable bool found { false };
+};
+
+bool VMInspector::isValidCell(Heap* heap, JSCell* candidate)
+{
+    HeapIterationScope iterationScope(*heap);
+    CellAddressCheckFunctor functor(candidate);
+    heap->objectSpace().forEachLiveCell(iterationScope, functor);
+    return functor.found;
+}
+
+bool VMInspector::isValidCodeBlock(ExecState* exec, CodeBlock* candidate)
+{
+    if (!ensureCurrentThreadOwnsJSLock(exec))
+        return false;
+
+    struct CodeBlockValidationFunctor {
+        CodeBlockValidationFunctor(CodeBlock* candidate)
+            : candidate(candidate)
+        {
+        }
+
+        bool operator()(CodeBlock* codeBlock) const
+        {
+            if (codeBlock == candidate)
+                found = true;
+            return found;
+        }
+
+        CodeBlock* candidate;
+        mutable bool found { false };
+    };
+
+    VM& vm = exec->vm();
+    CodeBlockValidationFunctor functor(candidate);
+    vm.heap.forEachCodeBlock(functor);
+    return functor.found;
+}
+
+CodeBlock* VMInspector::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) const
+        {
+            auto currentFrame = nextFrame++;
+            if (currentFrame == targetFrame) {
+                codeBlock = visitor->codeBlock();
+                return StackVisitor::Done;
+            }
+            return StackVisitor::Continue;
+        }
+
+        unsigned targetFrame;
+        mutable unsigned nextFrame { 0 };
+        mutable CodeBlock* codeBlock { nullptr };
+    };
+
+    FetchCodeBlockFunctor functor(frameNumber);
+    topCallFrame->iterate(functor);
+    return functor.codeBlock;
+}
+
+class PrintFrameFunctor {
+public:
+    enum Action {
+        PrintOne,
+        PrintAll
+    };
+
+    PrintFrameFunctor(Action action, unsigned framesToSkip)
+        : m_action(action)
+        , m_framesToSkip(framesToSkip)
+    {
+    }
+
+    StackVisitor::Status operator()(StackVisitor& visitor) const
+    {
+        m_currentFrame++;
+        if (m_currentFrame > m_framesToSkip) {
+            visitor->dump(WTF::dataFile(), Indenter(2), [&] (PrintStream& out) {
+                out.print("[", (m_currentFrame - m_framesToSkip - 1), "] ");
+            });
+        }
+        if (m_action == PrintOne && m_currentFrame > m_framesToSkip)
+            return StackVisitor::Done;
+        return StackVisitor::Continue;
+    }
+
+private:
+    Action m_action;
+    unsigned m_framesToSkip;
+    mutable unsigned m_currentFrame { 0 };
+};
+
+void VMInspector::printCallFrame(CallFrame* callFrame, unsigned framesToSkip)
+{
+    if (!ensureCurrentThreadOwnsJSLock(callFrame))
+        return;
+    PrintFrameFunctor functor(PrintFrameFunctor::PrintOne, framesToSkip);
+    callFrame->iterate(functor);
+}
+
+void VMInspector::printStack(CallFrame* topCallFrame, unsigned framesToSkip)
+{
+    if (!ensureCurrentThreadOwnsJSLock(topCallFrame))
+        return;
+    if (!topCallFrame)
+        return;
+    PrintFrameFunctor functor(PrintFrameFunctor::PrintAll, framesToSkip);
+    topCallFrame->iterate(functor);
+}
+
+void VMInspector::printValue(JSValue value)
+{
+    dataLog(value);
+}
+
 } // namespace JSC
index 3740d18..29872e9 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "CallFrame.h"
 #include "VM.h"
 #include <wtf/DoublyLinkedList.h>
 #include <wtf/Expected.h>
@@ -61,6 +62,17 @@ public:
     Expected<bool, Error> isValidExecutableMemory(const Locker&, void*);
     Expected<CodeBlock*, Error> codeBlockForMachinePC(const Locker&, void*);
 
+    JS_EXPORT_PRIVATE static bool currentThreadOwnsJSLock(ExecState*);
+    JS_EXPORT_PRIVATE static void gc(ExecState*);
+    JS_EXPORT_PRIVATE static void edenGC(ExecState*);
+    JS_EXPORT_PRIVATE static bool isInHeap(Heap*, void*);
+    JS_EXPORT_PRIVATE static bool isValidCell(Heap*, JSCell*);
+    JS_EXPORT_PRIVATE static bool isValidCodeBlock(ExecState*, CodeBlock*);
+    JS_EXPORT_PRIVATE static CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber);
+    JS_EXPORT_PRIVATE static void printCallFrame(CallFrame*, unsigned framesToSkip);
+    JS_EXPORT_PRIVATE static void printStack(CallFrame* topCallFrame, unsigned framesToSkip);
+    JS_EXPORT_PRIVATE static void printValue(JSValue);
+
 private:
     template <typename Functor> void iterate(const Functor& functor)
     {