Changeset 233129 in webkit


Ignore:
Timestamp:
Jun 23, 2018 8:48:25 AM (6 years ago)
Author:
mark.lam@apple.com
Message:

Add more debugging features to $vm.
https://bugs.webkit.org/show_bug.cgi?id=186947

Reviewed by Keith Miller.

Adding the following features:

We now have println in addition to print.
println automatically adds a '\n' at the end.
$vm.println("Hello");

We can now capture some info about a stack frame.
var currentFrame = $vm.callFrame();
Same as $vm.callFrame(0);
var callerCallerFrame = $vm.callFrame(2);

We can inspect the following values associated with the frame:
if (currentFrame.valid) {

$vm.println("name is ", currentFrame.name));

Note: For a WASM frame, all of these will be undefined.
$vm.println("callee is ", $vm.value(currentFrame.callee));
$vm.println("codeBlock is ", currentFrame.codeBlock);
$vm.println("unlinkedCodeBlock is ", currentFrame.unlinkedCodeBlock);
$vm.println("executable is ", currentFrame.executable);

}

Note that callee is a JSObject. I printed its $vm.value() because I wanted
to dataLog its JSValue instead of its toString() result.

Note that $vm.println() (and $vm.print()) can now print internal JSCells
(and Symbols) as JSValue dumps. It won't just fail on trying to do a
toString on a non-object.

Does what it says about enabling/disabling debugger mode.
$vm.enableDebuggerModeWhenIdle();
$vm.disableDebuggerModeWhenIdle();

  • tools/JSDollarVM.cpp:

(WTF::JSDollarVMCallFrame::JSDollarVMCallFrame):
(WTF::JSDollarVMCallFrame::createStructure):
(WTF::JSDollarVMCallFrame::create):
(WTF::JSDollarVMCallFrame::finishCreation):
(WTF::JSDollarVMCallFrame::addProperty):
(JSC::functionCallFrame):
(JSC::functionCodeBlockForFrame):
(JSC::codeBlockFromArg):
(JSC::doPrintln):
(JSC::functionPrint):
(JSC::functionPrintln):
(JSC::changeDebuggerModeWhenIdle):
(JSC::functionEnableDebuggerModeWhenIdle):
(JSC::functionDisableDebuggerModeWhenIdle):
(JSC::JSDollarVM::finishCreation):

Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r233124 r233129  
     12018-06-23  Mark Lam  <mark.lam@apple.com>
     2
     3        Add more debugging features to $vm.
     4        https://bugs.webkit.org/show_bug.cgi?id=186947
     5
     6        Reviewed by Keith Miller.
     7
     8        Adding the following features:
     9
     10            // We now have println in addition to print.
     11            // println automatically adds a '\n' at the end.
     12            $vm.println("Hello");
     13
     14            // We can now capture some info about a stack frame.
     15            var currentFrame = $vm.callFrame(); // Same as $vm.callFrame(0);
     16            var callerCallerFrame = $vm.callFrame(2);
     17
     18            // We can inspect the following values associated with the frame:
     19            if (currentFrame.valid) {
     20                $vm.println("name is ", currentFrame.name));
     21
     22                // Note: For a WASM frame, all of these will be undefined.
     23                $vm.println("callee is ", $vm.value(currentFrame.callee));
     24                $vm.println("codeBlock is ", currentFrame.codeBlock);
     25                $vm.println("unlinkedCodeBlock is ", currentFrame.unlinkedCodeBlock);
     26                $vm.println("executable is ", currentFrame.executable);
     27            }
     28
     29            // Note that callee is a JSObject.  I printed its $vm.value() because I wanted
     30            // to dataLog its JSValue instead of its toString() result.
     31
     32            // Note that $vm.println() (and $vm.print()) can now print internal JSCells
     33            // (and Symbols) as JSValue dumps. It won't just fail on trying to do a
     34            // toString on a non-object.
     35
     36            // Does what it says about enabling/disabling debugger mode.
     37            $vm.enableDebuggerModeWhenIdle();
     38            $vm.disableDebuggerModeWhenIdle();
     39
     40        * tools/JSDollarVM.cpp:
     41        (WTF::JSDollarVMCallFrame::JSDollarVMCallFrame):
     42        (WTF::JSDollarVMCallFrame::createStructure):
     43        (WTF::JSDollarVMCallFrame::create):
     44        (WTF::JSDollarVMCallFrame::finishCreation):
     45        (WTF::JSDollarVMCallFrame::addProperty):
     46        (JSC::functionCallFrame):
     47        (JSC::functionCodeBlockForFrame):
     48        (JSC::codeBlockFromArg):
     49        (JSC::doPrintln):
     50        (JSC::functionPrint):
     51        (JSC::functionPrintln):
     52        (JSC::changeDebuggerModeWhenIdle):
     53        (JSC::functionEnableDebuggerModeWhenIdle):
     54        (JSC::functionDisableDebuggerModeWhenIdle):
     55        (JSC::JSDollarVM::finishCreation):
     56
    1572018-06-22  Keith Miller  <keith_miller@apple.com>
    258
  • trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp

    r233122 r233129  
    11/*
    2  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5757namespace {
    5858
     59class JSDollarVMCallFrame : public JSDestructibleObject {
     60    using Base = JSDestructibleObject;
     61public:
     62    JSDollarVMCallFrame(VM& vm, Structure* structure)
     63        : Base(vm, structure)
     64    { }
     65
     66    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     67    {
     68        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     69    }
     70
     71    static JSDollarVMCallFrame* create(ExecState* exec, unsigned requestedFrameIndex)
     72    {
     73        VM& vm = exec->vm();
     74        JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     75        Structure* structure = createStructure(vm, globalObject, jsNull());
     76        JSDollarVMCallFrame* frame = new (NotNull, allocateCell<JSDollarVMCallFrame>(vm.heap, sizeof(JSDollarVMCallFrame))) JSDollarVMCallFrame(vm, structure);
     77        frame->finishCreation(vm, exec, requestedFrameIndex);
     78        return frame;
     79    }
     80
     81    void finishCreation(VM& vm, CallFrame* frame, unsigned requestedFrameIndex)
     82    {
     83        Base::finishCreation(vm);
     84
     85        auto addProperty = [&] (VM& vm, const char* name, JSValue value) {
     86            JSDollarVMCallFrame::addProperty(vm, name, value);
     87        };
     88
     89        unsigned frameIndex = 0;
     90        bool isValid = false;
     91        frame->iterate([&] (StackVisitor& visitor) {
     92
     93            if (frameIndex++ != requestedFrameIndex)
     94                return StackVisitor::Continue;
     95
     96            addProperty(vm, "name", jsString(&vm, visitor->functionName()));
     97
     98            if (visitor->callee().isCell())
     99                addProperty(vm, "callee", visitor->callee().asCell());
     100
     101            CodeBlock* codeBlock = visitor->codeBlock();
     102            if (!codeBlock) {
     103                addProperty(vm, "codeBlock", codeBlock);
     104                addProperty(vm, "unlinkedCodeBlock", codeBlock->unlinkedCodeBlock());
     105                addProperty(vm, "executable", codeBlock->ownerExecutable());
     106            }
     107            isValid = true;
     108
     109            return StackVisitor::Done;
     110        });
     111
     112        addProperty(vm, "valid", jsBoolean(isValid));
     113    }
     114
     115    DECLARE_INFO;
     116
     117private:
     118    void addProperty(VM& vm, const char* name, JSValue value)
     119    {
     120        Identifier identifier = Identifier::fromString(&vm, name);
     121        putDirect(vm, identifier, value);
     122    }
     123};
     124
     125const ClassInfo JSDollarVMCallFrame::s_info = { "CallFrame", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMCallFrame) };
     126
    59127class ElementHandleOwner;
    60128class Root;
     
    12461314}
    12471315
     1316// Gets a JSDollarVMCallFrame for a specified frame index.
     1317// Usage: var callFrame = $vm.callFrame(0) // frame 0 is the top frame.
     1318// Usage: var callFrame = $vm.callFrame() // implies frame 0 i.e. current frame.
     1319static EncodedJSValue JSC_HOST_CALL functionCallFrame(ExecState* exec)
     1320{
     1321    unsigned frameNumber = 1;
     1322    if (exec->argumentCount() >= 1) {
     1323        JSValue value = exec->uncheckedArgument(0);
     1324        if (!value.isUInt32())
     1325            return JSValue::encode(jsUndefined());
     1326
     1327        // We need to inc the frame number because the caller would consider
     1328        // its own frame as frame 0. Hence, we need discount the frame for this
     1329        // function.
     1330        frameNumber = value.asUInt32() + 1;
     1331    }
     1332
     1333    return JSValue::encode(JSDollarVMCallFrame::create(exec, frameNumber));
     1334}
     1335
    12481336// Gets a token for the CodeBlock for a specified frame index.
    12491337// Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame.
     1338// Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame.
    12501339static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
    12511340{
    1252     if (exec->argumentCount() < 1)
    1253         return JSValue::encode(jsUndefined());
    1254 
    1255     JSValue value = exec->uncheckedArgument(0);
    1256     if (!value.isUInt32())
    1257         return JSValue::encode(jsUndefined());
    1258 
    1259     // We need to inc the frame number because the caller would consider
    1260     // its own frame as frame 0. Hence, we need discount the frame for this
    1261     // function.
    1262     unsigned frameNumber = value.asUInt32() + 1;
     1341    unsigned frameNumber = 1;
     1342    if (exec->argumentCount() >= 1) {
     1343        JSValue value = exec->uncheckedArgument(0);
     1344        if (!value.isUInt32())
     1345            return JSValue::encode(jsUndefined());
     1346
     1347        // We need to inc the frame number because the caller would consider
     1348        // its own frame as frame 0. Hence, we need discount the frame for this
     1349        // function.
     1350        frameNumber = value.asUInt32() + 1;
     1351    }
     1352
    12631353    CodeBlock* codeBlock = VMInspector::codeBlockForFrame(exec, frameNumber);
    1264     // Though CodeBlock is a JSCell, it is not safe to return it directly back to JS code
    1265     // as it is an internal type that the JS code cannot handle. Hence, we first encode the
    1266     // CodeBlock* as a double token (which is safe for JS code to handle) before returning it.
    1267     return JSValue::encode(JSValue(bitwise_cast<double>(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(codeBlock)))));
     1354    if (codeBlock)
     1355        return JSValue::encode(codeBlock);
     1356    return JSValue::encode(jsUndefined());
    12681357}
    12691358
     
    12831372            else
    12841373                candidateCodeBlock = func->jsExecutable()->eitherCodeBlock();
    1285         }
    1286     } else if (value.isDouble()) {
    1287         // If the value is a double, it may be an encoded CodeBlock* that came from
    1288         // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's
    1289         // valid below before using.
    1290         candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
     1374        } else
     1375            candidateCodeBlock = reinterpret_cast<CodeBlock*>(value.asCell());
    12911376    }
    12921377
     
    13341419}
    13351420
    1336 // Prints a series of comma separate strings without inserting a newline.
    1337 // Usage: $vm.print(str1, str2, str3)
    1338 static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
     1421static EncodedJSValue doPrintln(ExecState* exec, bool addLineFeed)
    13391422{
    13401423    auto scope = DECLARE_THROW_SCOPE(exec->vm());
    13411424    for (unsigned i = 0; i < exec->argumentCount(); ++i) {
     1425        JSValue arg = exec->uncheckedArgument(i);
     1426        if (arg.isCell()
     1427            && !arg.isObject()
     1428            && !arg.isString()
     1429            && !arg.isBigInt()) {
     1430            dataLog(arg);
     1431            continue;
     1432        }
    13421433        String argStr = exec->uncheckedArgument(i).toWTFString(exec);
    13431434        RETURN_IF_EXCEPTION(scope, encodedJSValue());
    13441435        dataLog(argStr);
    13451436    }
     1437    if (addLineFeed)
     1438        dataLog("\n");
    13461439    return JSValue::encode(jsUndefined());
     1440}
     1441
     1442// Prints a series of comma separate strings without appending a newline.
     1443// Usage: $vm.print(str1, str2, str3)
     1444static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
     1445{
     1446    const bool addLineFeed = false;
     1447    return doPrintln(exec, addLineFeed);
     1448}
     1449
     1450// Prints a series of comma separate strings and appends a newline.
     1451// Usage: $vm.println(str1, str2, str3)
     1452static EncodedJSValue JSC_HOST_CALL functionPrintln(ExecState* exec)
     1453{
     1454    const bool addLineFeed = true;
     1455    return doPrintln(exec, addLineFeed);
    13471456}
    13481457
     
    17181827}
    17191828
     1829static EncodedJSValue changeDebuggerModeWhenIdle(ExecState* exec, DebuggerMode mode)
     1830{
     1831    bool newDebuggerMode = (mode == DebuggerOn);
     1832    if (Options::forceDebuggerBytecodeGeneration() == newDebuggerMode)
     1833        return JSValue::encode(jsUndefined());
     1834
     1835    VM* vm = &exec->vm();
     1836    vm->whenIdle([=] () {
     1837        Options::forceDebuggerBytecodeGeneration() = newDebuggerMode;
     1838        vm->deleteAllCode(PreventCollectionAndDeleteAllCode);
     1839    });
     1840    return JSValue::encode(jsUndefined());
     1841}
     1842
     1843static EncodedJSValue JSC_HOST_CALL functionEnableDebuggerModeWhenIdle(ExecState* exec)
     1844{
     1845    return changeDebuggerModeWhenIdle(exec, DebuggerOn);
     1846}
     1847
     1848static EncodedJSValue JSC_HOST_CALL functionDisableDebuggerModeWhenIdle(ExecState* exec)
     1849{
     1850    return changeDebuggerModeWhenIdle(exec, DebuggerOff);
     1851}
     1852
    17201853static EncodedJSValue JSC_HOST_CALL functionGlobalObjectCount(ExecState* exec)
    17211854{
     
    18331966    addFunction(vm, "edenGC", functionEdenGC, 0);
    18341967
     1968    addFunction(vm, "callFrame", functionCallFrame, 1);
    18351969    addFunction(vm, "codeBlockFor", functionCodeBlockFor, 1);
    18361970    addFunction(vm, "codeBlockForFrame", functionCodeBlockForFrame, 1);
     
    18391973
    18401974    addFunction(vm, "print", functionPrint, 1);
     1975    addFunction(vm, "println", functionPrintln, 1);
    18411976    addFunction(vm, "printCallFrame", functionPrintCallFrame, 0);
    18421977    addFunction(vm, "printStack", functionPrintStack, 0);
     
    18832018    addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
    18842019
     2020    addFunction(vm, "enableDebuggerModeWhenIdle", functionEnableDebuggerModeWhenIdle, 0);
     2021    addFunction(vm, "disableDebuggerModeWhenIdle", functionDisableDebuggerModeWhenIdle, 0);
     2022
    18852023    addFunction(vm, "globalObjectCount", functionGlobalObjectCount, 0);
    18862024    addFunction(vm, "globalObjectForObject", functionGlobalObjectForObject, 1);
Note: See TracChangeset for help on using the changeset viewer.