Changeset 233129 in webkit
- Timestamp:
- Jun 23, 2018 8:48:25 AM (6 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r233124 r233129 1 2018-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 1 57 2018-06-22 Keith Miller <keith_miller@apple.com> 2 58 -
trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp
r233122 r233129 1 1 /* 2 * Copyright (C) 2015-201 7Apple Inc. All rights reserved.2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 57 57 namespace { 58 58 59 class JSDollarVMCallFrame : public JSDestructibleObject { 60 using Base = JSDestructibleObject; 61 public: 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 117 private: 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 125 const ClassInfo JSDollarVMCallFrame::s_info = { "CallFrame", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMCallFrame) }; 126 59 127 class ElementHandleOwner; 60 128 class Root; … … 1246 1314 } 1247 1315 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. 1319 static 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 1248 1336 // Gets a token for the CodeBlock for a specified frame index. 1249 1337 // Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame. 1338 // Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame. 1250 1339 static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec) 1251 1340 { 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 1263 1353 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()); 1268 1357 } 1269 1358 … … 1283 1372 else 1284 1373 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()); 1291 1376 } 1292 1377 … … 1334 1419 } 1335 1420 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) 1421 static EncodedJSValue doPrintln(ExecState* exec, bool addLineFeed) 1339 1422 { 1340 1423 auto scope = DECLARE_THROW_SCOPE(exec->vm()); 1341 1424 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 } 1342 1433 String argStr = exec->uncheckedArgument(i).toWTFString(exec); 1343 1434 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 1344 1435 dataLog(argStr); 1345 1436 } 1437 if (addLineFeed) 1438 dataLog("\n"); 1346 1439 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) 1444 static 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) 1452 static EncodedJSValue JSC_HOST_CALL functionPrintln(ExecState* exec) 1453 { 1454 const bool addLineFeed = true; 1455 return doPrintln(exec, addLineFeed); 1347 1456 } 1348 1457 … … 1718 1827 } 1719 1828 1829 static 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 1843 static EncodedJSValue JSC_HOST_CALL functionEnableDebuggerModeWhenIdle(ExecState* exec) 1844 { 1845 return changeDebuggerModeWhenIdle(exec, DebuggerOn); 1846 } 1847 1848 static EncodedJSValue JSC_HOST_CALL functionDisableDebuggerModeWhenIdle(ExecState* exec) 1849 { 1850 return changeDebuggerModeWhenIdle(exec, DebuggerOff); 1851 } 1852 1720 1853 static EncodedJSValue JSC_HOST_CALL functionGlobalObjectCount(ExecState* exec) 1721 1854 { … … 1833 1966 addFunction(vm, "edenGC", functionEdenGC, 0); 1834 1967 1968 addFunction(vm, "callFrame", functionCallFrame, 1); 1835 1969 addFunction(vm, "codeBlockFor", functionCodeBlockFor, 1); 1836 1970 addFunction(vm, "codeBlockForFrame", functionCodeBlockForFrame, 1); … … 1839 1973 1840 1974 addFunction(vm, "print", functionPrint, 1); 1975 addFunction(vm, "println", functionPrintln, 1); 1841 1976 addFunction(vm, "printCallFrame", functionPrintCallFrame, 0); 1842 1977 addFunction(vm, "printStack", functionPrintStack, 0); … … 1883 2018 addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0); 1884 2019 2020 addFunction(vm, "enableDebuggerModeWhenIdle", functionEnableDebuggerModeWhenIdle, 0); 2021 addFunction(vm, "disableDebuggerModeWhenIdle", functionDisableDebuggerModeWhenIdle, 0); 2022 1885 2023 addFunction(vm, "globalObjectCount", functionGlobalObjectCount, 0); 1886 2024 addFunction(vm, "globalObjectForObject", functionGlobalObjectForObject, 1);
Note: See TracChangeset
for help on using the changeset viewer.