haikuwebkit/LayoutTests/inspector/debugger/tail-recursion.html

111 lines
4.3 KiB
HTML
Raw Permalink Normal View History

Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
<!doctype html>
<html>
<head>
<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
<script src="../../http/tests/inspector/debugger/debugger-test.js"></script>
<script src="./resources/tail-recursion.js"></script>
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
<script>
function test()
{
var scriptObject;
Web Inspector: Include RuntimeAgent in Workers - evaluate in Worker context https://bugs.webkit.org/show_bug.cgi?id=163835 <rdar://problem/28901465> Reviewed by Brian Burg. Source/WebCore: Tests: inspector/unit-tests/target-manager.html inspector/worker/runtime-basic.html * CMakeLists.txt: * WebCore.xcodeproj/project.pbxproj: * inspector/InspectorAllInOne.cpp: New file. * inspector/InspectorWebAgentBase.h: (WebCore::WorkerAgentContext::WorkerAgentContext): New agent context creation struct for Workers. * inspector/WorkerInspectorController.cpp: (WebCore::WorkerInspectorController::WorkerInspectorController): Create a RuntimeAgent for Workers. * inspector/WorkerRuntimeAgent.cpp: Added. (WebCore::WorkerRuntimeAgent::WorkerRuntimeAgent): (WebCore::WorkerRuntimeAgent::didCreateFrontendAndBackend): (WebCore::WorkerRuntimeAgent::willDestroyFrontendAndBackend): (WebCore::WorkerRuntimeAgent::injectedScriptForEval): * inspector/WorkerRuntimeAgent.h: Added. Workers currently only ever have a single execution context. Source/WebInspectorUI: This introduces the idea that the frontend may communication with multiple backend "Targets" which each have their own set of Agents. - WebInspector.Target - has its own list of Agents - has a InspectorBackend.Connection to communicate with the backend - WebInspector.mainTarget - always exists and represents the thing we are debugging (Page or JSContext) - WebInspector.targets / WebInspector.targetManager - management of all Targets - create new Targets for Workers This also slowly introduces the concept that Model objects may be tied to a specific Target: - WebInspector.RemoteObject - in order to evaluate JS and interact with this object we must know the target (Page or Worker) - when fetching PropertyDescriptors and other RemoteObjects we must continue to pass on the target Finally this makes the QuickConsole list Worker execution contexts in the context picker so that users can choose a Worker context and evaluate JavaScript in that context using the console. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Main.html: * UserInterface/Base/Main.js: (WebInspector.loaded): * UserInterface/Test.html: * UserInterface/Test/Test.js: (WebInspector.loaded): New files, strings, and managers. New global WebInspector.mainTarget. New convenience WebInspector.targets. * UserInterface/Protocol/Target.js: Added. (WebInspector.Target): (WebInspector.Target.prototype.get RuntimeAgent): (WebInspector.Target.prototype.get name): (WebInspector.Target.prototype.get type): (WebInspector.Target.prototype.get connection): (WebInspector.Target.prototype.get executionContext): (WebInspector.Target.prototype.get displayName): (WebInspector.Target.prototype._intializeMainTarget): (WebInspector.Target.prototype._initializeNonMainTarget): Target has some basic properties. * UserInterface/Controllers/TargetManager.js: (WebInspector.TargetManager): (WebInspector.TargetManager.prototype.get targets): (WebInspector.TargetManager.prototype.addTarget): (WebInspector.TargetManager.prototype.removeTarget): Holds the list of Targets and events when created / removed. Each target with a RuntimeAgent has an ExecutionContext. * UserInterface/Controllers/WorkerManager.js: (WebInspector.WorkerManager): (WebInspector.WorkerManager.prototype.workerCreated): (WebInspector.WorkerManager.prototype.workerTerminated): (WebInspector.WorkerManager.prototype.dispatchMessageFromWorker): Create / remove / dispatch on a Worker Target. * UserInterface/Protocol/InspectorBackend.js: (InspectorBackendClass): (InspectorBackendClass.prototype.registerCommand): (InspectorBackendClass.prototype.dispatch): (InspectorBackendClass.prototype.runAfterPendingDispatches): (InspectorBackendClass.prototype._agentForDomain): Keep the original implementations and just dispatch to the main connection. (InspectorBackend.Agent): (InspectorBackend.Agent.prototype.get connection): (InspectorBackend.Agent.prototype.set connection): (InspectorBackend.Agent.prototype.get dispatcher): We will share Agent implementations but just give new "copies" a different connection and dispatcher. (InspectorBackend.Command): (InspectorBackend.Command.create): (InspectorBackend.Command.prototype.invoke): (InspectorBackend.Command.prototype.supports): We continue to have a single Command instance on the Agent. However instead of using the hardcoded Agent on the Instance when evaluated as a function it uses the `this` object which should be an agent. This way: target1.RuntimeAgent.evaluate - `this` is target1 and we use the connection for that target target2.RuntimeAgent.evaluate - `this` is target2 and we use the connection for that target Unfortunately this breaks `RuntimeAgent.evaluate.invoke`. Currently this is solved by providing an extra parameter. In the case where we need to invoke on a particular agent we must provide the agent. target.RuntimeAgent.evaluate.invoke({options}, target.RuntimeAgent) This is unfortunate but only needed in a handful of places right now. (InspectorBackendClass.prototype._sendCommandToBackendWithCallback): Deleted. (InspectorBackendClass.prototype._sendCommandToBackendExpectingPromise): Deleted. (InspectorBackendClass.prototype._sendMessageToBackend): Deleted. (InspectorBackendClass.prototype._dispatchResponse): Deleted. (InspectorBackendClass.prototype._dispatchResponseToCallback): Deleted. (InspectorBackendClass.prototype._dispatchResponseToPromise): Deleted. (InspectorBackendClass.prototype._dispatchEvent): Deleted. (InspectorBackendClass.prototype._flushPendingScripts): Deleted. (InspectorBackend.Agent.prototype.get currentDispatchState): Deleted. (InspectorBackend.Command.prototype.deliverFailure): Deleted. * UserInterface/Protocol/Connection.js: Added. (InspectorBackend.Connection): (InspectorBackend.Connection.prototype.get target): (InspectorBackend.Connection.prototype.set target): (InspectorBackend.Connection.prototype.dispatch): (InspectorBackend.Connection.prototype.runAfterPendingDispatches): (InspectorBackend.Connection.prototype.sendMessageToBackend): (InspectorBackend.Connection.prototype._dispatchResponse): (InspectorBackend.Connection.prototype._dispatchResponseToCallback): (InspectorBackend.Connection.prototype._dispatchResponseToPromise): (InspectorBackend.Connection.prototype._dispatchEvent): (InspectorBackend.Connection.prototype._sendCommandToBackendWithCallback): (InspectorBackend.Connection.prototype._sendCommandToBackendExpectingPromise): (InspectorBackend.Connection.prototype._sendMessageToBackend): (InspectorBackend.Connection.prototype._flushPendingScripts): This extracts the Connection details into its own class. Although we make it appear as though a Target has a list of Agents, we actually have the Connection hold the list of Agents. Instead of cloning the entire Agent we just create a new object extended from the original Agent instance. This allows us to keep the same interface but just change the connection / dispatcher properties within the Agent. (InspectorBackend.MainConnection): (InspectorBackend.MainConnection.prototype.sendMessageToBackend): (InspectorBackend.WorkerConnection): (InspectorBackend.WorkerConnection.sendMessageToBackend): Two different kinds of connections. One for the Main connection and one for Workers. Currently the list of agents we expose on a Worker Target/Connection is hardcoded. * UserInterface/Models/ExecutionContext.js: (WebInspector.ExecutionContext): (WebInspector.ExecutionContext.prototype.get target): We may now have ExecutionContexts that mean a Page, Frames, and Workers. To do this we include the (target, executionContextId) tuple in this object. With this we have everything we need to evaluate JavaScript. * UserInterface/Controllers/RuntimeManager.js: (WebInspector.RuntimeManager): (WebInspector.RuntimeManager.prototype.get activeExecutionContext): (WebInspector.RuntimeManager.prototype.set activeExecutionContext): (WebInspector.RuntimeManager.prototype.get defaultExecutionContextIdentifier): Deleted. (WebInspector.RuntimeManager.prototype.set defaultExecutionContextIdentifier): Deleted. Update from contextId to a full ExecutionContext object. (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow.evalCallback): (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow): (WebInspector.RuntimeManager.prototype.saveResult): (WebInspector.RuntimeManager.prototype.getPropertiesForRemoteObject): (WebInspector.RuntimeManager.prototype._frameExecutionContextsCleared): * UserInterface/Controllers/FrameResourceManager.js: (WebInspector.FrameResourceManager.prototype.executionContextCreated): * UserInterface/Controllers/JavaScriptLogViewController.js: (WebInspector.JavaScriptLogViewController.prototype.consolePromptShouldCommitText): * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js: Anywhere that wants to use the "activeExecutionContext" must use the specific RuntimeAgent tied to that ExecutionContext's Target. * UserInterface/Models/PropertyDescriptor.js: (WebInspector.PropertyDescriptor.fromPayload): * UserInterface/Protocol/RemoteObject.js: (WebInspector.RemoteObject): (WebInspector.RemoteObject.createFakeRemoteObject): (WebInspector.RemoteObject.fromPrimitiveValue): (WebInspector.RemoteObject.fromPayload): (WebInspector.RemoteObject.prototype.getDisplayablePropertyDescriptors): (WebInspector.RemoteObject.prototype.deprecatedGetDisplayableProperties): (WebInspector.RemoteObject.prototype.setPropertyValue): (WebInspector.RemoteObject.prototype.getCollectionEntries): (WebInspector.RemoteObject.prototype.releaseWeakCollectionEntries): (WebInspector.RemoteObject.prototype.callFunction): (WebInspector.RemoteObject.prototype.callFunctionJSON): (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor.wrappedCallback): (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor): (WebInspector.RemoteObject.prototype.release): (WebInspector.RemoteObject.prototype._getPropertyDescriptors): (WebInspector.RemoteObject.prototype._getPropertyDescriptorsResolver): (WebInspector.RemoteObject.prototype._deprecatedGetProperties): RemoteObject and related Model Objects now must be tied to a specific Target, because we need to know which Target it belongs to in order to interact with it further. * UserInterface/Views/QuickConsole.js: (WebInspector.QuickConsole): (WebInspector.QuickConsole.prototype.get selectedExecutionContext): (WebInspector.QuickConsole.prototype.set selectedExecutionContext): (WebInspector.QuickConsole.prototype._executionContextPathComponentsToDisplay): (WebInspector.QuickConsole.prototype._rebuildExecutionContextPathComponents): (WebInspector.QuickConsole.prototype._framePageExecutionContextsChanged): (WebInspector.QuickConsole.prototype._frameExecutionContextsCleared): (WebInspector.QuickConsole.prototype._createExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._createExecutionContextPathComponentFromFrame): (WebInspector.QuickConsole.prototype._compareExecutionContextPathComponents): (WebInspector.QuickConsole.prototype._insertOtherExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._removeOtherExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._insertExecutionContextPathComponentForFrame): (WebInspector.QuickConsole.prototype._removeExecutionContextPathComponentForFrame): (WebInspector.QuickConsole.prototype._targetAdded): (WebInspector.QuickConsole.prototype._targetRemoved): (WebInspector.QuickConsole.prototype._pathComponentSelected): (WebInspector.QuickConsole.prototype.get selectedExecutionContextIdentifier): Deleted. (WebInspector.QuickConsole.prototype.set selectedExecutionContextIdentifier): Deleted. (WebInspector.QuickConsole.prototype._defaultExecutionContextChanged): Deleted. Update the code from executionContextId to ExecutionContext objects. Update the picker with ExecutionContextPathComponent for Workers (new Targets). Generalize and cleanup the code to make it easier to follow. LayoutTests: * inspector/unit-tests/target-manager-expected.txt: Added. * inspector/unit-tests/target-manager.html: Added. Unit test for TargetManager and its events with Worker creation. * inspector/worker/resources/worker-1.js: * inspector/worker/runtime-basic-expected.txt: Added. * inspector/worker/runtime-basic.html: Added. Test comparing RuntimeAgent between Main target and Worker target. * inspector/runtime/change-execution-context-identifier-expected.txt: * inspector/runtime/change-execution-context-identifier.html: RuntimeManager has been updated to have a full ExecutionContext object containing a Target + ContextId instead of just a ContextId. * inspector/console/console-api-expected.txt: * inspector/console/console-api.html: * inspector/console/console-table-expected.txt: * inspector/console/console-table.html: * inspector/debugger/tail-deleted-frames-from-vm-entry.html: * inspector/debugger/tail-deleted-frames.html: * inspector/debugger/tail-recursion.html: * inspector/model/remote-object-expected.txt: * inspector/model/remote-object-weak-collection-expected.txt: * inspector/model/remote-object-weak-collection.html: * inspector/model/remote-object.html: * platform/mac/inspector/model/remote-object-expected.txt: Introduce a better JSON Filter for RemoteObject in more tests. It is important that we filter the _target, because otherwise JSON.stringify would throw an error about cycles. Canonical link: https://commits.webkit.org/181797@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208009 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-27 22:19:12 +00:00
function remoteObjectJSONFilter(key, value) {
if (key === "_target" || key === "_listeners")
return undefined;
if (key === "_objectId" || key === "_stackTrace")
return "<filtered>";
return value;
}
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
function startTest() {
InspectorTest.log("Starting Test");
// 0 based indices.
var testInfos = [{line : 3, column : 8}, {line : 4, column : 8}];
for (let testInfo of testInfos) {
let location = scriptObject.createSourceCodeLocation(testInfo.line, testInfo.column);
Web Inspector: allow event breakpoints to be configured https://bugs.webkit.org/show_bug.cgi?id=215362 <rdar://problem/66932921> Reviewed by Brian Burg. Source/JavaScriptCore: This allows developers to do things like: - only pause when `window.event.type` is a certain value - ignore the first N pauses - evaluate JavaScript whenever an event listener is invoked without pausing * inspector/protocol/DOM.json: Add an `options` paramater to `DOM.setBreakpointForEventListener` to allow configuration. * inspector/protocol/DOMDebugger.json: Add an `options` paramater to `DOMDebugger.setEventBreakpoint` to allow configuration. * debugger/Breakpoint.h: (JSC::Breakpoint::id const): Added. (JSC::Breakpoint::sourceID const): Added. (JSC::Breakpoint::lineNumber const): Added. (JSC::Breakpoint::columnNumber const): Added. (JSC::Breakpoint::condition const): Added. (JSC::Breakpoint::actions const): Added. (JSC::Breakpoint::isAutoContinue const): Added. (JSC::Breakpoint::resetHitCount): Added. (JSC::Breakpoint::isLinked const): Added. (JSC::Breakpoint::isResolved const): Added. (JSC::BreakpointsList::~BreakpointsList): Deleted. * debugger/Breakpoint.cpp: Added. (JSC::Breakpoint::Action::Action): Added. (JSC::Breakpoint::create): Added. (JSC::Breakpoint::Breakpoint): Added. (JSC::Breakpoint::link): Added. (JSC::Breakpoint::resolve): Added. (JSC::Breakpoint::shouldPause): Added. Unify `JSC::Breakpoint` and `Inspector::ScriptBreakpoint`. * debugger/DebuggerPrimitives.h: * debugger/Debugger.h: * debugger/Debugger.cpp: (JSC::Debugger::Debugger): (JSC::Debugger::addObserver): Added. (JSC::Debugger::removeObserver): Added. (JSC::Debugger::canDispatchFunctionToObservers const): Added. (JSC::Debugger::dispatchFunctionToObservers): Added. (JSC::Debugger::sourceParsed): Added. (JSC::Debugger::toggleBreakpoint): (JSC::Debugger::applyBreakpoints): (JSC::Debugger::resolveBreakpoint): (JSC::Debugger::setBreakpoint): (JSC::Debugger::removeBreakpoint): (JSC::Debugger::didHitBreakpoint): Added. (JSC::Debugger::clearBreakpoints): (JSC::Debugger::evaluateBreakpointCondition): Added. (JSC::Debugger::evaluateBreakpointActions): Added. (JSC::Debugger::schedulePauseAtNextOpportunity): Added. (JSC::Debugger::cancelPauseAtNextOpportunity): Added. (JSC::Debugger::schedulePauseForSpecialBreakpoint): Added. (JSC::Debugger::cancelPauseForSpecialBreakpoint): Added. (JSC::Debugger::continueProgram): (JSC::Debugger::stepNextExpression): (JSC::Debugger::stepIntoStatement): (JSC::Debugger::stepOverStatement): (JSC::Debugger::stepOutOfFunction): (JSC::Debugger::pauseIfNeeded): (JSC::Debugger::handlePause): Added. (JSC::Debugger::exceptionOrCaughtValue): Added. (JSC::Debugger::atExpression): (JSC::Debugger::clearNextPauseState): (JSC::Debugger::willRunMicrotask): Added. (JSC::Debugger::didRunMicrotask): Added. (JSC::Debugger::hasBreakpoint): Deleted. (JSC::Debugger::setPauseOnNextStatement): Deleted. Unify `JSC::Debugger` and `Inspector::ScriptDebugServer` to simplify breakpoint logic. Introduce the concept of a "special breakpoint", which is essentially a `JSC::Breakpoint` that is expected to pause at the next opportunity but isn't tied to a particular location. As an example, whenever an event breakpoint is hit, instead of just pausing at the next opportunity, the newly managed `JSC::Breakpoint` is used as a "special breakpoint", allowing for it's configuration (ie.g. condition, ignore count, actions, auto-continue) to be used. * inspector/agents/InspectorDebuggerAgent.h: * inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::objectGroupForBreakpointAction): (Inspector::breakpointActionTypeForString): Added. (Inspector::parseBreakpointOptions): Added. (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::fromPayload): Added. (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint): Added. (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::createDebuggerBreakpoint const): Added. (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::matchesScriptURL const): Added. (Inspector::InspectorDebuggerAgent::debuggerBreakpointFromPayload): Added. (Inspector::InspectorDebuggerAgent::enable): (Inspector::InspectorDebuggerAgent::disable): (Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason): (Inspector::InspectorDebuggerAgent::handleConsoleAssert): (Inspector::InspectorDebuggerAgent::didScheduleAsyncCall): (Inspector::buildDebuggerLocation): (Inspector::InspectorDebuggerAgent::setBreakpointByUrl): (Inspector::InspectorDebuggerAgent::setBreakpoint): (Inspector::InspectorDebuggerAgent::didSetBreakpoint): (Inspector::InspectorDebuggerAgent::resolveBreakpoint): (Inspector::InspectorDebuggerAgent::removeBreakpoint): (Inspector::InspectorDebuggerAgent::continueToLocation): (Inspector::InspectorDebuggerAgent::schedulePauseAtNextOpportunity): Added. (Inspector::InspectorDebuggerAgent::cancelPauseAtNextOpportunity): Added. (Inspector::InspectorDebuggerAgent::schedulePauseForSpecialBreakpoint): Added. (Inspector::InspectorDebuggerAgent::cancelPauseForSpecialBreakpoint): Added. (Inspector::InspectorDebuggerAgent::pause): (Inspector::InspectorDebuggerAgent::resume): (Inspector::InspectorDebuggerAgent::didBecomeIdle): (Inspector::InspectorDebuggerAgent::sourceMapURLForScript): (Inspector::InspectorDebuggerAgent::didParseSource): (Inspector::InspectorDebuggerAgent::willRunMicrotask): (Inspector::InspectorDebuggerAgent::didRunMicrotask): (Inspector::InspectorDebuggerAgent::didPause): (Inspector::InspectorDebuggerAgent::breakpointActionSound): (Inspector::InspectorDebuggerAgent::breakpointActionProbe): (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState): (Inspector::matches): Deleted. (Inspector::buildObjectForBreakpointCookie): Deleted. (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): Deleted. (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): Deleted. (Inspector::InspectorDebuggerAgent::cancelPauseOnNextStatement): Deleted. Create a private `ProtocolBreakpoint` class that holds the data sent by the frontend. This is necessary because breakpoints in the frontend have a potentially one-to-many relationship with breakpoints in the backend, as the same script can be loaded many times on a page. Each of those scripts is independent, however, and can execute differently, meaning that the same breakpoint for each script also needs a different state (e.g. ignore count). As such, the `ProtocolBreakpoint` is effectively a template that is actualized whenever a new script is parsed that matches the URL of the `ProtocolBreakpoint` to create a `JSC::Breakpoint` that is used by the `JSC::Debugger`. `ProtocolBreakpoint` also parses breakpoint configurations. * inspector/InspectorEnvironment.h: * inspector/JSGlobalObjectScriptDebugServer.h: * inspector/JSGlobalObjectScriptDebugServer.cpp: (Inspector::JSGlobalObjectScriptDebugServer::JSGlobalObjectScriptDebugServer): (Inspector::JSGlobalObjectScriptDebugServer::attachDebugger): (Inspector::JSGlobalObjectScriptDebugServer::detachDebugger): (Inspector::JSGlobalObjectScriptDebugServer::runEventLoopWhilePaused): * inspector/agents/InspectorAuditAgent.h: * inspector/agents/InspectorAuditAgent.cpp: (Inspector::InspectorAuditAgent::run): * inspector/agents/InspectorRuntimeAgent.h: * inspector/agents/InspectorRuntimeAgent.cpp: (Inspector::setPauseOnExceptionsState): (Inspector::InspectorRuntimeAgent::evaluate): (Inspector::InspectorRuntimeAgent::callFunctionOn): (Inspector::InspectorRuntimeAgent::getPreview): (Inspector::InspectorRuntimeAgent::getProperties): (Inspector::InspectorRuntimeAgent::getDisplayableProperties): * inspector/agents/InspectorScriptProfilerAgent.cpp: * inspector/agents/JSGlobalObjectDebuggerAgent.h: Replace `Inspector::ScriptDebugServer` with `JSC::Debugger`. * runtime/JSMicrotask.cpp: (JSC::JSMicrotask::run): Drive-by: r248894 mistakenly omitted the call to notify the debugger that the microtask ran. * inspector/ScriptBreakpoint.h: Removed. * inspector/ScriptDebugListener.h: Removed. * inspector/ScriptDebugServer.h: Removed. * inspector/ScriptDebugServer.cpp: Removed. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: Source/WebCore: This allows developers to do things like: - only pause when `window.event.type` is a certain value - ignore the first N pauses - evaluate JavaScript whenever an event listener is invoked without pausing Tests: inspector/dom/breakpoint-for-event-listener.html inspector/dom-debugger/event-animation-frame-breakpoints.html inspector/dom-debugger/event-interval-breakpoints.html inspector/dom-debugger/event-listener-breakpoints.html inspector/dom-debugger/event-timeout-breakpoints.html * inspector/agents/InspectorDOMAgent.h: * inspector/agents/InspectorDOMAgent.cpp: (WebCore::InspectorDOMAgent::getEventListenersForNode): (WebCore::InspectorDOMAgent::setBreakpointForEventListener): (WebCore::InspectorDOMAgent::removeBreakpointForEventListener): (WebCore::InspectorDOMAgent::buildObjectForEventListener): (WebCore::InspectorDOMAgent::breakpointForEventListener): (WebCore::InspectorDOMAgent::hasBreakpointForEventListener): Deleted. * inspector/agents/InspectorDOMDebuggerAgent.h: * inspector/agents/InspectorDOMDebuggerAgent.cpp: (WebCore::InspectorDOMDebuggerAgent::disable): (WebCore::InspectorDOMDebuggerAgent::mainFrameNavigated): (WebCore::InspectorDOMDebuggerAgent::setEventBreakpoint): (WebCore::InspectorDOMDebuggerAgent::removeEventBreakpoint): (WebCore::InspectorDOMDebuggerAgent::willHandleEvent): (WebCore::InspectorDOMDebuggerAgent::didHandleEvent): (WebCore::InspectorDOMDebuggerAgent::willFireTimer): (WebCore::InspectorDOMDebuggerAgent::didFireTimer): * inspector/agents/page/PageDOMDebuggerAgent.h: * inspector/agents/page/PageDOMDebuggerAgent.cpp: (WebCore::PageDOMDebuggerAgent::disable): (WebCore::PageDOMDebuggerAgent::mainFrameNavigated): (WebCore::PageDOMDebuggerAgent::willFireAnimationFrame): (WebCore::PageDOMDebuggerAgent::didFireAnimationFrame): (WebCore::PageDOMDebuggerAgent::setAnimationFrameBreakpoint): * inspector/agents/worker/WorkerDOMDebuggerAgent.h: * inspector/agents/worker/WorkerDOMDebuggerAgent.cpp: (WebCore::WorkerDOMDebuggerAgent::setAnimationFrameBreakpoint): Keep a `JSC::Breakpoint` for each event breakpoint instead of a simple `bool`, allowing for configuration when the breakpoint is first set. When any of these breakpoints are hit, pass it to the `JSC::Debugger` as a "special breakpoint", which behaves the same as "pause ASAP" but also supports a condition, an ignore count, actions, and auto-continue. Reset the hit count for any of these "special breakpoints" that persist across Web Inspector sessions when the main frame navigates. * inspector/PageScriptDebugServer.h: * inspector/PageScriptDebugServer.cpp: (WebCore::PageScriptDebugServer::PageScriptDebugServer): (WebCore::PageScriptDebugServer::attachDebugger): (WebCore::PageScriptDebugServer::detachDebugger): (WebCore::PageScriptDebugServer::didPause): (WebCore::PageScriptDebugServer::didContinue): (WebCore::PageScriptDebugServer::runEventLoopWhilePaused): (WebCore::PageScriptDebugServer::runEventLoopWhilePausedInternal): (WebCore::PageScriptDebugServer::isContentScript const): (WebCore::PageScriptDebugServer::reportException const): * inspector/WorkerScriptDebugServer.h: * inspector/WorkerScriptDebugServer.cpp: (WebCore::WorkerScriptDebugServer::WorkerScriptDebugServer): (WebCore::WorkerScriptDebugServer::attachDebugger): (WebCore::WorkerScriptDebugServer::detachDebugger): (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused): (WebCore::WorkerScriptDebugServer::reportException const): * inspector/agents/page/PageDebuggerAgent.h: * inspector/agents/page/PageDebuggerAgent.cpp: (WebCore::PageDebuggerAgent::sourceMapURLForScript): Replace `Inspector::ScriptDebugServer` with `JSC::Debugger`. * inspector/TimelineRecordFactory.h: * inspector/TimelineRecordFactory.cpp: (WebCore::TimelineRecordFactory::createProbeSampleData): * inspector/agents/InspectorTimelineAgent.h: * inspector/agents/InspectorTimelineAgent.cpp: (WebCore::InspectorTimelineAgent::internalStart): (WebCore::InspectorTimelineAgent::internalStop): (WebCore::InspectorTimelineAgent::breakpointActionProbe): Replace `Inspector::ScriptBreakpoint` with `JSC::Breakpoint`. * inspector/InspectorInstrumentation.h: (WebCore::InspectorInstrumentation::didHandleEvent): (WebCore::InspectorInstrumentation::didFireTimer): * inspector/InspectorInstrumentation.cpp: (WebCore::InspectorInstrumentation::didHandleEventImpl): (WebCore::InspectorInstrumentation::didFireTimerImpl): (WebCore::InspectorInstrumentation::didCommitLoadImpl): (WebCore::InspectorInstrumentation::didFireAnimationFrameImpl): * dom/EventTarget.cpp: (WebCore::EventTarget::innerInvokeEventListeners): * page/DOMTimer.cpp: (WebCore::DOMTimer::fired): When notifying Web Inspector that activity did occur, include all information previously included when notifying Web Inspector that that activity was about to occur so that Web Inspector can know whether a pause for the "special breakpoint" for that activity is still scheduled and if so cancel it. Source/WebInspectorUI: This allows developers to do things like: - only pause when `window.event.type` is a certain value - ignore the first N pauses - evaluate JavaScript whenever an event listener is invoked without pausing * UserInterface/Models/Breakpoint.js: (WI.Breakpoint): (WI.Breakpoint.prototype.toJSON): (WI.Breakpoint.prototype.get special): Added. (WI.Breakpoint.prototype.get removable): Added. (WI.Breakpoint.prototype.get editable): Added. (WI.Breakpoint.prototype.set condition): (WI.Breakpoint.prototype.get ignoreCount): (WI.Breakpoint.prototype.set ignoreCount): (WI.Breakpoint.prototype.get autoContinue): (WI.Breakpoint.prototype.set autoContinue): (WI.Breakpoint.prototype.get actions): (WI.Breakpoint.prototype.get probeActions): (WI.Breakpoint.prototype.cycleToNextMode): (WI.Breakpoint.prototype.createAction): (WI.Breakpoint.prototype.recreateAction): (WI.Breakpoint.prototype.removeAction): (WI.Breakpoint.prototype.clearActions): (WI.Breakpoint.prototype.remove): Added. (WI.Breakpoint.prototype.optionsToProtocol): Added. (WI.Breakpoint.prototype.breakpointActionDidChange): (WI.Breakpoint.fromJSON): Deleted. (WI.Breakpoint.prototype.get sourceCodeLocation): Deleted. (WI.Breakpoint.prototype.get contentIdentifier): Deleted. (WI.Breakpoint.prototype.get scriptIdentifier): Deleted. (WI.Breakpoint.prototype.get target): Deleted. (WI.Breakpoint.prototype.get identifier): Deleted. (WI.Breakpoint.prototype.set identifier): Deleted. (WI.Breakpoint.prototype.get resolved): Deleted. (WI.Breakpoint.prototype.set resolved): Deleted. (WI.Breakpoint.prototype.saveIdentityToCookie): Deleted. (WI.Breakpoint.prototype._isSpecial): Deleted. (WI.Breakpoint.prototype._sourceCodeLocationLocationChanged): Deleted. (WI.Breakpoint.prototype._sourceCodeLocationDisplayLocationChanged): Deleted. * UserInterface/Models/DOMBreakpoint.js: (WI.DOMBreakpoint): (WI.DOMBreakpoint.fromJSON): Added. (WI.DOMBreakpoint.prototype.remove): Added. (WI.DOMBreakpoint.prototype.toJSON): (WI.DOMBreakpoint.deserialize): Deleted. (WI.DOMBreakpoint.prototype.get disabled): Deleted. (WI.DOMBreakpoint.prototype.set disabled): Deleted. * UserInterface/Models/EventBreakpoint.js: (WI.EventBreakpoint): (WI.EventBreakpoint.fromJSON): Added. (WI.EventBreakpoint.prototype.get special): Added. (WI.EventBreakpoint.prototype.get editable): Added. (WI.EventBreakpoint.prototype.remove): Added. (WI.EventBreakpoint.prototype.saveIdentityToCookie): (WI.EventBreakpoint.prototype.toJSON): (WI.EventBreakpoint.deserialize): Deleted. (WI.EventBreakpoint.prototype.get disabled): Deleted. (WI.EventBreakpoint.prototype.set disabled): Deleted. * UserInterface/Models/JavaScriptBreakpoint.js: Copied from UserInterface/Models/Breakpoint.js. (WI.JavaScriptBreakpoint): (WI.JavaScriptBreakpoint.fromJSON): (WI.JavaScriptBreakpoint.prototype.toJSON): (WI.JavaScriptBreakpoint.prototype.get sourceCodeLocation): (WI.JavaScriptBreakpoint.prototype.get contentIdentifier): (WI.JavaScriptBreakpoint.prototype.get scriptIdentifier): (WI.JavaScriptBreakpoint.prototype.get target): (WI.JavaScriptBreakpoint.prototype.get special): Added. (WI.JavaScriptBreakpoint.prototype.get removable): Added. (WI.JavaScriptBreakpoint.prototype.get editable): Added. (WI.JavaScriptBreakpoint.prototype.get identifier): (WI.JavaScriptBreakpoint.prototype.set identifier): (WI.JavaScriptBreakpoint.prototype.get resolved): (WI.JavaScriptBreakpoint.prototype.set resolved): (WI.JavaScriptBreakpoint.prototype.remove): Added. (WI.JavaScriptBreakpoint.prototype.saveIdentityToCookie): (WI.JavaScriptBreakpoint.prototype._isSpecial): (WI.JavaScriptBreakpoint.prototype._sourceCodeLocationLocationChanged): (WI.JavaScriptBreakpoint.prototype._sourceCodeLocationDisplayLocationChanged): * UserInterface/Models/URLBreakpoint.js: (WI.URLBreakpoint): (WI.URLBreakpoint.fromJSON): Added. (WI.URLBreakpoint.prototype.get special): Added. (WI.URLBreakpoint.prototype.remove): Added. (WI.URLBreakpoint.prototype.toJSON): (WI.URLBreakpoint.deserialize): Deleted. (WI.URLBreakpoint.prototype.get disabled): Deleted. (WI.URLBreakpoint.prototype.set disabled): Deleted. Rename `WI.Breakpoint` to `WI.JavaScriptBreakpoint` and use `WI.Breakpoint` as a new common base class for all breakpoint types, allowing more logic to be shared (e.g. disabled state). Additionally, breakpoints are now able to - determine whether or not they're - special - removable - editable (i.e. configurable) - remove themselves without the caller needing to know what manager to consult with. * UserInterface/Controllers/DOMManager.js: (WI.DOMManager): (WI.DOMManager.supportsEventListenerBreakpointConfiguration): Added. (WI.DOMManager.prototype.setBreakpointForEventListener): (WI.DOMManager.prototype.removeBreakpointForEventListener): (WI.DOMManager.prototype._setEventBreakpoint): Added. (WI.DOMManager.prototype._removeEventBreakpoint): Added. (WI.DOMManager.prototype._handleEventBreakpointEditablePropertyChanged): Added. (WI.DOMManager.prototype._handleEventBreakpointActionsChanged): Added. (WI.DOMManager.prototype._updateEventBreakpoint): Deleted. Keep track of configuration changes for specific listener breakpoints. * UserInterface/Controllers/DOMDebuggerManager.js: (WI.DOMDebuggerManager): (WI.DOMDebuggerManager.prototype.initializeTarget): (WI.DOMDebuggerManager.prototype.addDOMBreakpoint): (WI.DOMDebuggerManager.prototype.removeDOMBreakpoint): (WI.DOMDebuggerManager.prototype.addEventBreakpoint): (WI.DOMDebuggerManager.prototype.removeEventBreakpoint): (WI.DOMDebuggerManager.prototype.addURLBreakpoint): (WI.DOMDebuggerManager.prototype.removeURLBreakpoint): (WI.DOMDebuggerManager.prototype._commandArgumentsForEventBreakpoint): Added. (WI.DOMDebuggerManager.prototype._setEventBreakpoint): Added. (WI.DOMDebuggerManager.prototype._removeEventBreakpoint): Added. (WI.DOMDebuggerManager.prototype._handleEventBreakpointDisabledStateChanged): Added. (WI.DOMDebuggerManager.prototype._handleEventBreakpointEditablePropertyChanged): Added. (WI.DOMDebuggerManager.prototype._handleEventBreakpointActionsChanged): Added. (WI.DOMDebuggerManager.prototype.isBreakpointSpecial): Deleted. (WI.DOMDebuggerManager.prototype._updateEventBreakpoint): Deleted. Keep track of configuration changes for special event breakpoints. Store special event breakpoints inside `WI.objectStores.eventBreakpoints`. * UserInterface/Controllers/DebuggerManager.js: (WI.DebuggerManager): (WI.DebuggerManager.prototype.addBreakpoint): (WI.DebuggerManager.prototype.removeBreakpoint): (WI.DebuggerManager.prototype.addProbesForBreakpoint): Added. (WI.DebuggerManager.prototype.removeProbesForBreakpoint): Added. (WI.DebuggerManager.prototype.updateProbesForBreakpoint): Added. (WI.DebuggerManager.prototype._setBreakpoint): (WI.DebuggerManager.prototype._breakpointEditablePropertyDidChange): (WI.DebuggerManager.prototype._handleBreakpointActionsDidChange): (WI.DebuggerManager.prototype.isBreakpointRemovable): Deleted. (WI.DebuggerManager.prototype.isBreakpointSpecial): Deleted. (WI.DebuggerManager.prototype.isBreakpointEditable): Deleted. (WI.DebuggerManager.prototype._debuggerBreakpointActionType): Deleted. (WI.DebuggerManager.prototype._debuggerBreakpointOptions): Deleted. (WI.DebuggerManager.prototype._addProbesForBreakpoint): Deleted. (WI.DebuggerManager.prototype._removeProbesForBreakpoint): Deleted. (WI.DebuggerManager.prototype._updateProbesForBreakpoint): Deleted. Replace `WI.Breakpoint` with `WI.JavaScriptBreakpoint`. Probes now support `WI.EventBreakpoint` in addition to `WI.JavaScriptBreakpoint`. * UserInterface/Controllers/BreakpointPopoverController.js: (WI.BreakpointPopoverController.prototype.appendContextMenuItems): (WI.BreakpointPopoverController.prototype._createPopoverContent): Allow any breakpoint instead of only `WI.JavaScriptBreakpoint`. Drive-by: the existing `ignoreCount` value wasn't being used to populate the `<input>`. * UserInterface/Views/BreakpointTreeElement.js: (WI.BreakpointTreeElement.prototype.ondelete): (WI.BreakpointTreeElement.prototype.get listenerSet): Added. (WI.BreakpointTreeElement.prototype.updateStatus): Added. (WI.BreakpointTreeElement.prototype.updateTitles): Added. (WI.BreakpointTreeElement.prototype.get breakpoint): Deleted. (WI.BreakpointTreeElement.prototype.get filterableData): Deleted. (WI.BreakpointTreeElement.prototype._updateTitles): Deleted. (WI.BreakpointTreeElement.prototype._updateStatus): Deleted. (WI.BreakpointTreeElement.prototype._breakpointLocationDidChange): Deleted. * UserInterface/Views/BreakpointTreeElement.css: (.item.breakpoint .status > .status-image): (.item.breakpoint.paused .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.paused .icon): Added. (.item.breakpoint .status > .status-image.resolved): Deleted. (body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.selected .status > .status-image.resolved): Deleted. (.item.breakpoint .subtitle.formatted-location): Deleted. (.breakpoint-debugger-statement-icon .icon): Deleted. (.breakpoint-exception-icon .icon): Deleted. (.breakpoint-assertion-icon .icon): Deleted. (.breakpoint-microtask-icon .icon): Deleted. (.breakpoint-paused-icon .icon): Deleted. (.breakpoint-generic-line-icon .icon): Deleted. (.breakpoint-generic-line-icon .icon > span): Deleted. (.data-updated.breakpoint-generic-line-icon .icon > span): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-debugger-statement-icon .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-exception-icon .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-assertion-icon .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-microtask-icon .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-paused-icon .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint-generic-line-icon .icon): Deleted. * UserInterface/Views/DOMBreakpointTreeElement.js: (WI.DOMBreakpointTreeElement): (WI.DOMBreakpointTreeElement.prototype.onattach): Deleted. (WI.DOMBreakpointTreeElement.prototype.ondetach): Deleted. (WI.DOMBreakpointTreeElement.prototype.ondelete): Deleted. (WI.DOMBreakpointTreeElement.prototype.onenter): Deleted. (WI.DOMBreakpointTreeElement.prototype.onspace): Deleted. (WI.DOMBreakpointTreeElement.prototype.populateContextMenu): Deleted. (WI.DOMBreakpointTreeElement.prototype._statusImageElementClicked): Deleted. (WI.DOMBreakpointTreeElement.prototype._statusImageElementFocused): Deleted. (WI.DOMBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted. (WI.DOMBreakpointTreeElement.prototype._toggleBreakpoint): Deleted. (WI.DOMBreakpointTreeElement.prototype._updateStatus): Deleted. * UserInterface/Views/DOMBreakpointTreeElement.css: (.item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added. (.item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added. (.item.breakpoint.dom.node-removed:not(.paused) .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.dom.node-removed:not(.paused) .icon): Added. (.breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted. (.breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted. (.breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted. * UserInterface/Views/EventBreakpointTreeElement.js: (WI.EventBreakpointTreeElement): (WI.EventBreakpointTreeElement.prototype.onattach): Deleted. (WI.EventBreakpointTreeElement.prototype.ondetach): Deleted. (WI.EventBreakpointTreeElement.prototype.ondelete): Deleted. (WI.EventBreakpointTreeElement.prototype.onenter): Deleted. (WI.EventBreakpointTreeElement.prototype.onspace): Deleted. (WI.EventBreakpointTreeElement.prototype.populateContextMenu): Deleted. (WI.EventBreakpointTreeElement.prototype._statusImageElementClicked): Deleted. (WI.EventBreakpointTreeElement.prototype._statusImageElementFocused): Deleted. (WI.EventBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted. (WI.EventBreakpointTreeElement.prototype._toggleBreakpoint): Deleted. (WI.EventBreakpointTreeElement.prototype._updateStatus): Deleted. * UserInterface/Views/EventBreakpointTreeElement.css: (.item.breakpoint.event.animation-frame:not(.paused) .icon): Added. (.item.breakpoint.event.interval:not(.paused) .icon): Added. (.item.breakpoint.event.listener:not(.paused) .icon): Added. (.item.breakpoint.event.timeout:not(.paused) .icon): Added. (@media(prefers-color-scheme: dark) .item.breakpoint.event.animation-frame:not(.paused) .icon): Added. (@media(prefers-color-scheme: dark) .item.breakpoint.event.interval:not(.paused) .icon): Added. (@media(prefers-color-scheme: dark) .item.breakpoint.event.listener:not(.paused) .icon): Added. (@media(prefers-color-scheme: dark) .item.breakpoint.event.timeout:not(.paused) .icon): Added. (.breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted. (.breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted. (.breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted. (.breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted. (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted. (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted. (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted. (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted. * UserInterface/Views/JavaScriptBreakpointTreeElement.js: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js. (WI.JavaScriptBreakpointTreeElement): (WI.JavaScriptBreakpointTreeElement.prototype.get filterableData): (WI.JavaScriptBreakpointTreeElement.prototype.updateStatus): Added. (WI.JavaScriptBreakpointTreeElement.prototype.updateTitles): Added. (WI.JavaScriptBreakpointTreeElement.prototype._breakpointLocationDidChange): * UserInterface/Views/JavaScriptBreakpointTreeElement.css: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.css. (.item.breakpoint.javascript .status > .status-image): Added. (.item.breakpoint.javascript .status > .status-image.resolved): Added. (body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.javascript.selected .status > .status-image.resolved): Added. (.item.breakpoint.javascript .subtitle.formatted-location): Added. (.item.breakpoint.javascript.line .icon): Added. (.item.breakpoint.javascript.line .icon > span): Added. (.data-updated.item.breakpoint.javascript.line .icon > span): Added. (.item.breakpoint.javascript.debugger-statement .icon): Added. (.item.breakpoint.javascript.exception .icon): Added. (.item.breakpoint.javascript.assertion .icon): Added. (.item.breakpoint.javascript.microtask .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.line .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.debugger-statement .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.exception .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.assertion .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.microtask .icon): Added. * UserInterface/Views/URLBreakpointTreeElement.js: (WI.URLBreakpointTreeElement): (WI.URLBreakpointTreeElement.prototype.onattach): Deleted. (WI.URLBreakpointTreeElement.prototype.ondetach): Deleted. (WI.URLBreakpointTreeElement.prototype.ondelete): Deleted. (WI.URLBreakpointTreeElement.prototype.onenter): Deleted. (WI.URLBreakpointTreeElement.prototype.onspace): Deleted. (WI.URLBreakpointTreeElement.prototype.populateContextMenu): Deleted. (WI.URLBreakpointTreeElement.prototype._statusImageElementClicked): Deleted. (WI.URLBreakpointTreeElement.prototype._statusImageElementFocused): Deleted. (WI.URLBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted. (WI.URLBreakpointTreeElement.prototype._toggleBreakpoint): Deleted. (WI.URLBreakpointTreeElement.prototype._updateStatus): Deleted. * UserInterface/Views/URLBreakpointTreeElement.css: (.item.breakpoint.url .subtitle): Added. (.item.breakpoint.url:not(.paused) .icon): Added. (@media (prefers-color-scheme: dark) .item.breakpoint.url:not(.paused) .icon): Added. (.breakpoint.url .subtitle): Deleted. (.breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted. (@media (prefers-color-scheme: dark) .breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted. Rename `WI.BreakpointTreeElement` to `WI.JavaScriptBreakpointTreeElement` and use `WI.BreakpointTreeElement` as a new common base class for all breakpoint tree elements, allowing more logic and styles to be shared (e.g. disabled state). * UserInterface/Views/SourcesNavigationSidebarPanel.js: (WI.SourcesNavigationSidebarPanel): (WI.SourcesNavigationSidebarPanel.prototype.closed): (WI.SourcesNavigationSidebarPanel.prototype._insertDebuggerTreeElement): (WI.SourcesNavigationSidebarPanel.prototype._compareJavaScriptBreakpointTreeElements): Added. (WI.SourcesNavigationSidebarPanel.prototype._addBreakpoint): (WI.SourcesNavigationSidebarPanel.prototype._removeAllBreakpoints): (WI.SourcesNavigationSidebarPanel.prototype._breakpointsBeneathTreeElement): (WI.SourcesNavigationSidebarPanel.prototype._addIssue): (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection): (WI.SourcesNavigationSidebarPanel.prototype._handleTreeSelectionDidChange): (WI.SourcesNavigationSidebarPanel.prototype._handleBreakpointElementAddedOrRemoved): (WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu.addToggleForSpecialEventBreakpoint): (WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu): (WI.SourcesNavigationSidebarPanel.prototype._handleDebuggerObjectDisplayLocationDidChange): (WI.SourcesNavigationSidebarPanel.prototype._compareBreakpointTreeElements): Deleted. * UserInterface/Models/ProbeSet.js: (WI.ProbeSet): (WI.ProbeSet.prototype.createProbe): (WI.ProbeSet.prototype.willRemove): * UserInterface/Controllers/TimelineManager.js: (WI.TimelineManager.prototype._processRecord): * UserInterface/Views/ProbeSetDetailsSection.js: (WI.ProbeSetDetailsSection): * UserInterface/Views/ProbeDetailsSidebarPanel.js: (WI.ProbeDetailsSidebarPanel.prototype.inspect): * UserInterface/Views/SourceCodeTextEditor.js: (WI.SourceCodeTextEditor): (WI.SourceCodeTextEditor.prototype.close): (WI.SourceCodeTextEditor.prototype.textEditorBreakpointAdded): * UserInterface/Views/TextResourceContentView.js: (WI.TextResourceContentView.prototype.get supplementalRepresentedObjects): (WI.TextResourceContentView.prototype._probeSetsChanged): Probes now support `WI.EventBreakpoint` in addition to `WI.JavaScriptBreakpoint`. * UserInterface/Views/ContentView.js: (WI.ContentView.createFromRepresentedObject): (WI.ContentView.resolvedRepresentedObjectForRepresentedObject): (WI.ContentView.isViewable): * UserInterface/Views/ContextMenuUtilities.js: (WI.appendContextMenuItemsForSourceCode): Replace `WI.Breakpoint` with `WI.JavaScriptBreakpoint`. * UserInterface/Views/DOMTreeContentView.js: (WI.DOMTreeContentView): Replace `WI.DOMBreakpoint` with `WI.Breakpoint`. * UserInterface/Views/EventListenerSectionGroup.js: (WI.EventListenerSectionGroup): * UserInterface/Views/EventListenerSectionGroup.css: (.event-listener-section > .content input[type="checkbox"] + .go-to-arrow): Added. (.event-listener-section > .content input[type="checkbox"]:not(:checked) + .go-to-arrow): Added. Add a go-to arrow next to the Breakpoint checkbox that reveals the `WI.EventBreakpoint` in the Sources Tab. * UserInterface/Views/BreakpointActionView.js: (WI.BreakpointActionView.prototype._appendActionButtonClicked): Drive-by: minor code cleanup. * UserInterface/Views/CallFrameTreeElement.js: (WI.CallFrameTreeElement.prototype.populateContextMenu): Drive-by: include source code location context menu items. * UserInterface/Base/Setting.js: * UserInterface/Main.html: * UserInterface/Test.html: LayoutTests: * inspector/dom-debugger/resources/event-breakpoint-utilities.js: (TestPage.registerInitializer.InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases): Added. (TestPage.registerInitializer.InspectorTest.EventBreakpoint.async teardown): (TestPage.registerInitializer.InspectorTest.EventBreakpoint.createBreakpoint): (TestPage.registerInitializer.InspectorTest.EventBreakpoint.removeBreakpoint): * inspector/dom/breakpoint-for-event-listener.html: * inspector/dom/breakpoint-for-event-listener-expected.txt: * inspector/dom-debugger/event-animation-frame-breakpoints.html: * inspector/dom-debugger/event-animation-frame-breakpoints-expected.txt: * inspector/dom-debugger/event-interval-breakpoints.html: * inspector/dom-debugger/event-interval-breakpoints-expected.txt: * inspector/dom-debugger/event-listener-breakpoints.html: * inspector/dom-debugger/event-listener-breakpoints-expected.txt: * inspector/dom-debugger/event-timeout-breakpoints.html: * inspector/dom-debugger/event-timeout-breakpoints-expected.txt: Add tests for new event breakpoint configuration options. * http/tests/inspector/debugger/debugger-test.js: (TestPage.registerInitializer.InspectorTest.startTracingBreakpoints): * http/tests/inspector/resources/probe-test.js: (TestPage.registerInitializer.ProtocolTest.Probe.installTracingListeners): * inspector/debugger/breakpoint-action-eval.html: * inspector/debugger/breakpoint-action-log.html: * inspector/debugger/breakpoint-columns.html: * inspector/debugger/breakpoint-scope.html: * inspector/debugger/debugger-stack-overflow.html: * inspector/debugger/pause-reason.html: * inspector/debugger/probe-manager-add-remove-actions.html: * inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html: * inspector/debugger/tail-deleted-frames-this-value.html: * inspector/debugger/tail-recursion.html: * inspector/worker/debugger-pause.html: * inspector/worker/debugger-shared-breakpoint.html: Update existing breakpoint tests to use new model objects. Canonical link: https://commits.webkit.org/228551@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@266074 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-08-24 17:34:12 +00:00
let breakpoint = new WI.JavaScriptBreakpoint(location);
WI.debuggerManager.addBreakpoint(breakpoint);
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
}
InspectorTest.evaluateInPage("startRecurse()");
}
let numBreakpointHits = 0;
WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.CallFramesDidChange, function(event) {
var activeCallFrame = WI.debuggerManager.activeCallFrame;
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
if (!activeCallFrame)
return;
numBreakpointHits++;
var stopLocation = "line: " + activeCallFrame.sourceCodeLocation.lineNumber + ", column: " + activeCallFrame.sourceCodeLocation.columnNumber;
InspectorTest.log("\n\n------------------------------------");
InspectorTest.log("Hit breakpoint at " + stopLocation);
InspectorTest.log("numBreakpointHits: " + numBreakpointHits);
const numFramesToInspect = 50;
InspectorTest.log("Going to look at the top " + numFramesToInspect + " frames.");
InspectorTest.log("------------------------------------");
let targetData = WI.debuggerManager.dataForTarget(WI.debuggerManager.activeCallFrame.target);
Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts https://bugs.webkit.org/show_bug.cgi?id=164136 <rdar://problem/29028462> Reviewed by Brian Burg. Source/WebCore: Tests: inspector/worker/debugger-pause.html inspector/worker/debugger-scripts.html * CMakeLists.txt: * WebCore.xcodeproj/project.pbxproj: * inspector/InspectorAllInOne.cpp: New file. * inspector/PageDebuggerAgent.h: * inspector/WorkerDebuggerAgent.cpp: Added. (WebCore::WorkerDebuggerAgent::WorkerDebuggerAgent): (WebCore::WorkerDebuggerAgent::~WorkerDebuggerAgent): (WebCore::WorkerDebuggerAgent::breakpointActionLog): (WebCore::WorkerDebuggerAgent::injectedScriptForEval): * inspector/WorkerDebuggerAgent.h: Added. DebuggerAgent customizations for Workers. * inspector/WorkerInspectorController.cpp: (WebCore::WorkerInspectorController::WorkerInspectorController): Add the new agent. * inspector/WorkerScriptDebugServer.cpp: (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused): Implement the nested run loop for Workers. Source/WebInspectorUI: By implementing DebuggerAgent, Workers will inform the frontend about Scripts that evaluate in the Worker's VM and the Worker VM can pause and send the pausing CallFrames to the frontend. This means that WebInspector.Script and WebInspector.CallFrame will need to be made target aware. This also means that each Target will have its own set of debugger data, such as the list of scripts and pause data like the pause reason / call frames. Previously all this data was managed by DebuggerManager. With this change we split that data out of DebuggerManager to be per-target DebuggerData. DebuggerManager keeps `activeCallFrame` but the list of scripts and pause data have moved into `DebuggerData` which is per-target, accessed through DebuggerManager's new dataForTarget(target) method. Finally we make a few changes to the UserInterface to make Workers and their scripts, appear grouped together. The Resources sidebar previously had a single top level item for the Main Frame, which has all its resources as its children (potentially grouped into folders). With this change, each Worker gets its own top level item as well, and the Worker's subresources (imported scripts) become its children. We also now associate a single mainResource with Targets. In the case of Workers, we assume and assert that this is a Script. If this were to ever change we would need to adjust the assumptions. * UserInterface/Main.html: * UserInterface/Test.html: New files. * UserInterface/Base/Main.js: * UserInterface/Test/Test.js: Add WebInspector.assumingMainTarget to fill in all the places where we assume the main target right now, but would need to handle non-main targets as other agents are implemented in workers. For example profile data that assumes the main target right now could be worker targets when we implement ScriptProfiler / Heap agents. * UserInterface/Protocol/Connection.js: (InspectorBackend.WorkerConnection): * UserInterface/Protocol/Target.js: (WebInspector.Target): (WebInspector.Target.prototype.get DebuggerAgent): (WebInspector.Target.prototype.get mainResource): (WebInspector.Target.prototype.set mainResource): (WebInspector.WorkerTarget.prototype.initialize): (WebInspector.WorkerTarget): Include DebuggerAgent in Targets. Include a mainResource for Worker Targets. * UserInterface/Protocol/DebuggerObserver.js: (WebInspector.DebuggerObserver.prototype.scriptParsed): (WebInspector.DebuggerObserver.prototype.breakpointResolved): (WebInspector.DebuggerObserver.prototype.paused): (WebInspector.DebuggerObserver.prototype.resumed): Pass the target on to managers when necessary. * UserInterface/Models/DebuggerData.js: Added. (WebInspector.DebuggerData): (WebInspector.DebuggerData.prototype.get target): (WebInspector.DebuggerData.prototype.get callFrames): (WebInspector.DebuggerData.prototype.get pauseReason): (WebInspector.DebuggerData.prototype.get pauseData): (WebInspector.DebuggerData.prototype.get scripts): (WebInspector.DebuggerData.prototype.scriptForIdentifier): (WebInspector.DebuggerData.prototype.scriptsForURL): (WebInspector.DebuggerData.prototype.reset): (WebInspector.DebuggerData.prototype.addScript): (WebInspector.DebuggerData.prototype.pause): (WebInspector.DebuggerData.prototype.unpause): Extract per-target data from DebuggerManager. This includes the list of scripts evaluated in a Target, and any pause data for this target such as the pause reason and call frames. * UserInterface/Controllers/DebuggerManager.js: (WebInspector.DebuggerManager.prototype.dataForTarget): (WebInspector.DebuggerManager.prototype.get pauseReason): Deleted. (WebInspector.DebuggerManager.prototype.get pauseData): Deleted. (WebInspector.DebuggerManager.prototype.get callFrames): Deleted. (WebInspector.DebuggerManager.prototype.reset): New way to access per-target debugger data. (WebInspector.DebuggerManager.prototype.initializeTarget): When a new Target is created, synchronize frontend state with the target. Things like the list of breakpoints and global breakpoint states. (WebInspector.DebuggerManager.prototype.scriptForIdentifier): (WebInspector.DebuggerManager.prototype.scriptsForURL): Convenience accessors for scripts must now provide a Target. (WebInspector.DebuggerManager.prototype.get knownNonResourceScripts): This is a convenience accessors for a list of all scripts across all targets so this handles getting the list across all targets. (WebInspector.DebuggerManager.prototype.pause): (WebInspector.DebuggerManager.prototype.resume): (WebInspector.DebuggerManager.prototype.stepOver): (WebInspector.DebuggerManager.prototype.stepInto): (WebInspector.DebuggerManager.prototype.stepOut): (WebInspector.DebuggerManager.prototype.continueToLocation): Stepping commands affect the current target with the active call frame. Eventually we will change Pause and Resume behavior to affect all targets. (WebInspector.DebuggerManager.prototype.addBreakpoint): (WebInspector.DebuggerManager.prototype.breakpointResolved): (WebInspector.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint): (WebInspector.DebuggerManager.prototype._setBreakpoint): (WebInspector.DebuggerManager.prototype._removeBreakpoint): Breakpoints should be set on all targets, but we need a way to set them on a specific target, when initializing an individual target when we want to inform that single target of all of the breakpoints. (WebInspector.DebuggerManager.prototype._breakpointDisabledStateDidChange): (WebInspector.DebuggerManager.prototype._updateBreakOnExceptionsState): Changing global breakpoint state should inform all targets. (WebInspector.DebuggerManager.prototype.scriptDidParse): Associate Scripts with a Target. Identify the main resource of a Worker Target and set it as soon as we can. (WebInspector.DebuggerManager.prototype.debuggerDidPause): (WebInspector.DebuggerManager.prototype.debuggerDidResume): (WebInspector.DebuggerManager.prototype._sourceCodeLocationFromPayload): (WebInspector.DebuggerManager.prototype._scopeChainFromPayload): (WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload): (WebInspector.DebuggerManager.prototype._mainResourceDidChange): (WebInspector.DebuggerManager.prototype._didResumeInternal): Pausing and resuming now happens per-target, so associate created model objects (CallFrame, ScopeChain objects) and any other necessary data with the target. * UserInterface/Models/Breakpoint.js: (WebInspector.Breakpoint): (WebInspector.Breakpoint.prototype.get target): (WebInspector.Breakpoint.prototype.get info): * UserInterface/Models/CallFrame.js: (WebInspector.CallFrame): (WebInspector.CallFrame.prototype.get target): (WebInspector.CallFrame.fromDebuggerPayload): (WebInspector.CallFrame.fromPayload): * UserInterface/Models/ConsoleMessage.js: (WebInspector.ConsoleMessage): * UserInterface/Models/Script.js: (WebInspector.Script): (WebInspector.Script.prototype.get target): (WebInspector.Script.prototype.isMainResource): (WebInspector.Script.prototype.requestContentFromBackend): (WebInspector.Script.prototype._resolveResource): * UserInterface/Models/StackTrace.js: (WebInspector.StackTrace.fromPayload): (WebInspector.StackTrace.fromString): * UserInterface/Models/ProbeManager.js: (WebInspector.ProbeManager.prototype.didSampleProbe): * UserInterface/Models/Probe.js: (WebInspector.ProbeSample): * UserInterface/Views/ConsoleMessageView.js: (WebInspector.ConsoleMessageView.prototype._appendLocationLink): (WebInspector.ConsoleMessageView.prototype._formatParameterAsString): Associate model objects with a specific target where necessary. * UserInterface/Views/ObjectTreeBaseTreeElement.js: (WebInspector.ObjectTreeBaseTreeElement.prototype._appendMenusItemsForObject): * UserInterface/Controllers/RuntimeManager.js: (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow): * UserInterface/Protocol/RemoteObject.js: (WebInspector.RemoteObject.prototype.findFunctionSourceCodeLocation): Use target specific DebuggerAgent where necessary. * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js: * UserInterface/Controllers/TimelineManager.js: (WebInspector.TimelineManager.prototype._callFramesFromPayload): * UserInterface/Models/ScriptTimelineRecord.js: (WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload.profileNodeFromPayload): * UserInterface/Views/EventListenerSectionGroup.js: (WebInspector.EventListenerSectionGroup.prototype._functionTextOrLink): (WebInspector.EventListenerSectionGroup): * UserInterface/Views/HeapSnapshotInstanceDataGridNode.js: (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode.node.shortestGCRootPath.): (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populateWindowPreview): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populatePreview): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._mouseoverHandler.appendPathRow): * UserInterface/Views/ProfileDataGridNode.js: (WebInspector.ProfileDataGridNode.prototype.iconClassName): (WebInspector.ProfileDataGridNode.prototype.filterableDataForColumn): (WebInspector.ProfileDataGridNode.prototype._displayContent): Use assumed main target and audit these when the Worker gets more Agents. * UserInterface/Controllers/FrameResourceManager.js: (WebInspector.FrameResourceManager.prototype._initiatorSourceCodeLocationFromPayload): This will always be the main target because only the main target has access to the DOM. * UserInterface/Views/SourceCodeTextEditor.js: (WebInspector.SourceCodeTextEditor.prototype.get target): (WebInspector.SourceCodeTextEditor.prototype.customPerformSearch): (WebInspector.SourceCodeTextEditor.prototype.textEditorGutterContextMenu): (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression.populate): (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression): (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails): (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction): Update target specific actions to use the proper target's agents. * UserInterface/Views/TargetTreeElement.js: Added. (WebInspector.TargetTreeElement): (WebInspector.TargetTreeElement.prototype.get target): (WebInspector.TargetTreeElement.prototype.onexpand): (WebInspector.TargetTreeElement.prototype.oncollapse): Add a new tree element for a Target. We currently assume that the main resource for a Target will be a Script right now, as is the case for Web Workers. This simply remembers its expanded or collapsed state and has a better icon. * UserInterface/Views/ResourceIcons.css: (body:matches(.mac-platform, .windows-platform) .script.worker-icon .icon): (body:matches(.mac-platform, .windows-platform) .large .script.worker-icon .icon): * UserInterface/Images/WorkerScript.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument.png. * UserInterface/Images/WorkerScript@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument@2x.png. * UserInterface/Images/WorkerScriptLarge.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge.png. * UserInterface/Images/WorkerScriptLarge@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge@2x.png. Improve icon for a Worker's main resource script. * UserInterface/Views/ResourceSidebarPanel.js: (WebInspector.ResourceSidebarPanel): (WebInspector.ResourceSidebarPanel.prototype._scriptWasAdded): (WebInspector.ResourceSidebarPanel.prototype._scriptsCleared): (WebInspector.ResourceSidebarPanel.prototype._addScriptForNonMainTarget): (WebInspector.ResourceSidebarPanel.prototype._addTargetWithMainResource): (WebInspector.ResourceSidebarPanel.prototype._targetRemoved): * UserInterface/Views/SearchSidebarPanel.js: (WebInspector.SearchSidebarPanel.prototype.performSearch.searchScripts): (WebInspector.SearchSidebarPanel.prototype._searchTreeElementForScript): * UserInterface/Views/OpenResourceDialog.js: (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline.createTreeElement): (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline): (WebInspector.OpenResourceDialog.prototype.didDismissDialog): (WebInspector.OpenResourceDialog.prototype.didPresentDialog): (WebInspector.OpenResourceDialog.prototype._addResourcesForFrame): (WebInspector.OpenResourceDialog.prototype._addScriptsForTarget): (WebInspector.OpenResourceDialog.prototype._scriptAdded): (WebInspector.OpenResourceDialog): * UserInterface/Views/DebuggerSidebarPanel.js: (WebInspector.DebuggerSidebarPanel.prototype._addTreeElementForSourceCodeToTreeOutline): (WebInspector.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange): (WebInspector.DebuggerSidebarPanel.prototype._debuggerActiveCallFrameDidChange): (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection): Include scripts from non-main targets in sidebars. LayoutTests: * inspector/worker/debugger-pause-expected.txt: Added. * inspector/worker/debugger-pause.html: Added. * inspector/worker/debugger-scripts-expected.txt: Added. * inspector/worker/debugger-scripts.html: Added. * inspector/worker/resources/worker-debugger-pause.js: Added. * inspector/worker/resources/worker-import-1.js: Added. * inspector/worker/resources/worker-scripts.js: Added. New tests for Debugger features in a Worker. * inspector/debugger/break-on-exception-throw-in-promise.html: * inspector/debugger/break-on-exception.html: * inspector/debugger/break-on-uncaught-exception.html: * inspector/debugger/evaluateOnCallFrame-CommandLineAPI.html: * inspector/debugger/pause-reason.html: * inspector/debugger/paused-scopes.html: * inspector/debugger/resources/log-pause-location.js: * inspector/debugger/stepping/stepInto.html: * inspector/debugger/stepping/stepOut.html: * inspector/debugger/stepping/stepOver.html: * inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html: * inspector/debugger/tail-deleted-frames-from-vm-entry.html: * inspector/debugger/tail-deleted-frames-this-value.html: * inspector/debugger/tail-deleted-frames.html: * inspector/debugger/tail-recursion.html: Most debugger data moved from DebuggerManager into DebuggerData for a target. Update tests that access such data like pauseReason / pauseData / callFrames. Canonical link: https://commits.webkit.org/182063@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208304 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 21:51:36 +00:00
let callFrames = targetData.callFrames;
InspectorTest.assert(callFrames.length > numFramesToInspect); // We just look at top 50. This isn't a precise number. But it gets at the gist of the debugging experience.
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
for (let i = 0; i < numFramesToInspect; i++) {
Web Inspector: Include DebuggerAgent in Workers - see, pause, and step through scripts https://bugs.webkit.org/show_bug.cgi?id=164136 <rdar://problem/29028462> Reviewed by Brian Burg. Source/WebCore: Tests: inspector/worker/debugger-pause.html inspector/worker/debugger-scripts.html * CMakeLists.txt: * WebCore.xcodeproj/project.pbxproj: * inspector/InspectorAllInOne.cpp: New file. * inspector/PageDebuggerAgent.h: * inspector/WorkerDebuggerAgent.cpp: Added. (WebCore::WorkerDebuggerAgent::WorkerDebuggerAgent): (WebCore::WorkerDebuggerAgent::~WorkerDebuggerAgent): (WebCore::WorkerDebuggerAgent::breakpointActionLog): (WebCore::WorkerDebuggerAgent::injectedScriptForEval): * inspector/WorkerDebuggerAgent.h: Added. DebuggerAgent customizations for Workers. * inspector/WorkerInspectorController.cpp: (WebCore::WorkerInspectorController::WorkerInspectorController): Add the new agent. * inspector/WorkerScriptDebugServer.cpp: (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused): Implement the nested run loop for Workers. Source/WebInspectorUI: By implementing DebuggerAgent, Workers will inform the frontend about Scripts that evaluate in the Worker's VM and the Worker VM can pause and send the pausing CallFrames to the frontend. This means that WebInspector.Script and WebInspector.CallFrame will need to be made target aware. This also means that each Target will have its own set of debugger data, such as the list of scripts and pause data like the pause reason / call frames. Previously all this data was managed by DebuggerManager. With this change we split that data out of DebuggerManager to be per-target DebuggerData. DebuggerManager keeps `activeCallFrame` but the list of scripts and pause data have moved into `DebuggerData` which is per-target, accessed through DebuggerManager's new dataForTarget(target) method. Finally we make a few changes to the UserInterface to make Workers and their scripts, appear grouped together. The Resources sidebar previously had a single top level item for the Main Frame, which has all its resources as its children (potentially grouped into folders). With this change, each Worker gets its own top level item as well, and the Worker's subresources (imported scripts) become its children. We also now associate a single mainResource with Targets. In the case of Workers, we assume and assert that this is a Script. If this were to ever change we would need to adjust the assumptions. * UserInterface/Main.html: * UserInterface/Test.html: New files. * UserInterface/Base/Main.js: * UserInterface/Test/Test.js: Add WebInspector.assumingMainTarget to fill in all the places where we assume the main target right now, but would need to handle non-main targets as other agents are implemented in workers. For example profile data that assumes the main target right now could be worker targets when we implement ScriptProfiler / Heap agents. * UserInterface/Protocol/Connection.js: (InspectorBackend.WorkerConnection): * UserInterface/Protocol/Target.js: (WebInspector.Target): (WebInspector.Target.prototype.get DebuggerAgent): (WebInspector.Target.prototype.get mainResource): (WebInspector.Target.prototype.set mainResource): (WebInspector.WorkerTarget.prototype.initialize): (WebInspector.WorkerTarget): Include DebuggerAgent in Targets. Include a mainResource for Worker Targets. * UserInterface/Protocol/DebuggerObserver.js: (WebInspector.DebuggerObserver.prototype.scriptParsed): (WebInspector.DebuggerObserver.prototype.breakpointResolved): (WebInspector.DebuggerObserver.prototype.paused): (WebInspector.DebuggerObserver.prototype.resumed): Pass the target on to managers when necessary. * UserInterface/Models/DebuggerData.js: Added. (WebInspector.DebuggerData): (WebInspector.DebuggerData.prototype.get target): (WebInspector.DebuggerData.prototype.get callFrames): (WebInspector.DebuggerData.prototype.get pauseReason): (WebInspector.DebuggerData.prototype.get pauseData): (WebInspector.DebuggerData.prototype.get scripts): (WebInspector.DebuggerData.prototype.scriptForIdentifier): (WebInspector.DebuggerData.prototype.scriptsForURL): (WebInspector.DebuggerData.prototype.reset): (WebInspector.DebuggerData.prototype.addScript): (WebInspector.DebuggerData.prototype.pause): (WebInspector.DebuggerData.prototype.unpause): Extract per-target data from DebuggerManager. This includes the list of scripts evaluated in a Target, and any pause data for this target such as the pause reason and call frames. * UserInterface/Controllers/DebuggerManager.js: (WebInspector.DebuggerManager.prototype.dataForTarget): (WebInspector.DebuggerManager.prototype.get pauseReason): Deleted. (WebInspector.DebuggerManager.prototype.get pauseData): Deleted. (WebInspector.DebuggerManager.prototype.get callFrames): Deleted. (WebInspector.DebuggerManager.prototype.reset): New way to access per-target debugger data. (WebInspector.DebuggerManager.prototype.initializeTarget): When a new Target is created, synchronize frontend state with the target. Things like the list of breakpoints and global breakpoint states. (WebInspector.DebuggerManager.prototype.scriptForIdentifier): (WebInspector.DebuggerManager.prototype.scriptsForURL): Convenience accessors for scripts must now provide a Target. (WebInspector.DebuggerManager.prototype.get knownNonResourceScripts): This is a convenience accessors for a list of all scripts across all targets so this handles getting the list across all targets. (WebInspector.DebuggerManager.prototype.pause): (WebInspector.DebuggerManager.prototype.resume): (WebInspector.DebuggerManager.prototype.stepOver): (WebInspector.DebuggerManager.prototype.stepInto): (WebInspector.DebuggerManager.prototype.stepOut): (WebInspector.DebuggerManager.prototype.continueToLocation): Stepping commands affect the current target with the active call frame. Eventually we will change Pause and Resume behavior to affect all targets. (WebInspector.DebuggerManager.prototype.addBreakpoint): (WebInspector.DebuggerManager.prototype.breakpointResolved): (WebInspector.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint): (WebInspector.DebuggerManager.prototype._setBreakpoint): (WebInspector.DebuggerManager.prototype._removeBreakpoint): Breakpoints should be set on all targets, but we need a way to set them on a specific target, when initializing an individual target when we want to inform that single target of all of the breakpoints. (WebInspector.DebuggerManager.prototype._breakpointDisabledStateDidChange): (WebInspector.DebuggerManager.prototype._updateBreakOnExceptionsState): Changing global breakpoint state should inform all targets. (WebInspector.DebuggerManager.prototype.scriptDidParse): Associate Scripts with a Target. Identify the main resource of a Worker Target and set it as soon as we can. (WebInspector.DebuggerManager.prototype.debuggerDidPause): (WebInspector.DebuggerManager.prototype.debuggerDidResume): (WebInspector.DebuggerManager.prototype._sourceCodeLocationFromPayload): (WebInspector.DebuggerManager.prototype._scopeChainFromPayload): (WebInspector.DebuggerManager.prototype._scopeChainNodeFromPayload): (WebInspector.DebuggerManager.prototype._mainResourceDidChange): (WebInspector.DebuggerManager.prototype._didResumeInternal): Pausing and resuming now happens per-target, so associate created model objects (CallFrame, ScopeChain objects) and any other necessary data with the target. * UserInterface/Models/Breakpoint.js: (WebInspector.Breakpoint): (WebInspector.Breakpoint.prototype.get target): (WebInspector.Breakpoint.prototype.get info): * UserInterface/Models/CallFrame.js: (WebInspector.CallFrame): (WebInspector.CallFrame.prototype.get target): (WebInspector.CallFrame.fromDebuggerPayload): (WebInspector.CallFrame.fromPayload): * UserInterface/Models/ConsoleMessage.js: (WebInspector.ConsoleMessage): * UserInterface/Models/Script.js: (WebInspector.Script): (WebInspector.Script.prototype.get target): (WebInspector.Script.prototype.isMainResource): (WebInspector.Script.prototype.requestContentFromBackend): (WebInspector.Script.prototype._resolveResource): * UserInterface/Models/StackTrace.js: (WebInspector.StackTrace.fromPayload): (WebInspector.StackTrace.fromString): * UserInterface/Models/ProbeManager.js: (WebInspector.ProbeManager.prototype.didSampleProbe): * UserInterface/Models/Probe.js: (WebInspector.ProbeSample): * UserInterface/Views/ConsoleMessageView.js: (WebInspector.ConsoleMessageView.prototype._appendLocationLink): (WebInspector.ConsoleMessageView.prototype._formatParameterAsString): Associate model objects with a specific target where necessary. * UserInterface/Views/ObjectTreeBaseTreeElement.js: (WebInspector.ObjectTreeBaseTreeElement.prototype._appendMenusItemsForObject): * UserInterface/Controllers/RuntimeManager.js: (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow): * UserInterface/Protocol/RemoteObject.js: (WebInspector.RemoteObject.prototype.findFunctionSourceCodeLocation): Use target specific DebuggerAgent where necessary. * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js: * UserInterface/Controllers/TimelineManager.js: (WebInspector.TimelineManager.prototype._callFramesFromPayload): * UserInterface/Models/ScriptTimelineRecord.js: (WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload.profileNodeFromPayload): * UserInterface/Views/EventListenerSectionGroup.js: (WebInspector.EventListenerSectionGroup.prototype._functionTextOrLink): (WebInspector.EventListenerSectionGroup): * UserInterface/Views/HeapSnapshotInstanceDataGridNode.js: (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode.node.shortestGCRootPath.): (WebInspector.HeapSnapshotInstanceDataGridNode.logHeapSnapshotNode): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populateWindowPreview): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._populatePreview): (WebInspector.HeapSnapshotInstanceDataGridNode.prototype._mouseoverHandler.appendPathRow): * UserInterface/Views/ProfileDataGridNode.js: (WebInspector.ProfileDataGridNode.prototype.iconClassName): (WebInspector.ProfileDataGridNode.prototype.filterableDataForColumn): (WebInspector.ProfileDataGridNode.prototype._displayContent): Use assumed main target and audit these when the Worker gets more Agents. * UserInterface/Controllers/FrameResourceManager.js: (WebInspector.FrameResourceManager.prototype._initiatorSourceCodeLocationFromPayload): This will always be the main target because only the main target has access to the DOM. * UserInterface/Views/SourceCodeTextEditor.js: (WebInspector.SourceCodeTextEditor.prototype.get target): (WebInspector.SourceCodeTextEditor.prototype.customPerformSearch): (WebInspector.SourceCodeTextEditor.prototype.textEditorGutterContextMenu): (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression.populate): (WebInspector.SourceCodeTextEditor.prototype._tokenTrackingControllerHighlightedJavaScriptExpression): (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction.didGetDetails): (WebInspector.SourceCodeTextEditor.prototype._showPopoverForFunction): Update target specific actions to use the proper target's agents. * UserInterface/Views/TargetTreeElement.js: Added. (WebInspector.TargetTreeElement): (WebInspector.TargetTreeElement.prototype.get target): (WebInspector.TargetTreeElement.prototype.onexpand): (WebInspector.TargetTreeElement.prototype.oncollapse): Add a new tree element for a Target. We currently assume that the main resource for a Target will be a Script right now, as is the case for Web Workers. This simply remembers its expanded or collapsed state and has a better icon. * UserInterface/Views/ResourceIcons.css: (body:matches(.mac-platform, .windows-platform) .script.worker-icon .icon): (body:matches(.mac-platform, .windows-platform) .large .script.worker-icon .icon): * UserInterface/Images/WorkerScript.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument.png. * UserInterface/Images/WorkerScript@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocument@2x.png. * UserInterface/Images/WorkerScriptLarge.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge.png. * UserInterface/Images/WorkerScriptLarge@2x.png: Renamed from Source/WebInspectorUI/UserInterface/Images/WorkerDocumentLarge@2x.png. Improve icon for a Worker's main resource script. * UserInterface/Views/ResourceSidebarPanel.js: (WebInspector.ResourceSidebarPanel): (WebInspector.ResourceSidebarPanel.prototype._scriptWasAdded): (WebInspector.ResourceSidebarPanel.prototype._scriptsCleared): (WebInspector.ResourceSidebarPanel.prototype._addScriptForNonMainTarget): (WebInspector.ResourceSidebarPanel.prototype._addTargetWithMainResource): (WebInspector.ResourceSidebarPanel.prototype._targetRemoved): * UserInterface/Views/SearchSidebarPanel.js: (WebInspector.SearchSidebarPanel.prototype.performSearch.searchScripts): (WebInspector.SearchSidebarPanel.prototype._searchTreeElementForScript): * UserInterface/Views/OpenResourceDialog.js: (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline.createTreeElement): (WebInspector.OpenResourceDialog.prototype._populateResourceTreeOutline): (WebInspector.OpenResourceDialog.prototype.didDismissDialog): (WebInspector.OpenResourceDialog.prototype.didPresentDialog): (WebInspector.OpenResourceDialog.prototype._addResourcesForFrame): (WebInspector.OpenResourceDialog.prototype._addScriptsForTarget): (WebInspector.OpenResourceDialog.prototype._scriptAdded): (WebInspector.OpenResourceDialog): * UserInterface/Views/DebuggerSidebarPanel.js: (WebInspector.DebuggerSidebarPanel.prototype._addTreeElementForSourceCodeToTreeOutline): (WebInspector.DebuggerSidebarPanel.prototype._debuggerCallFramesDidChange): (WebInspector.DebuggerSidebarPanel.prototype._debuggerActiveCallFrameDidChange): (WebInspector.DebuggerSidebarPanel.prototype._updatePauseReasonSection): Include scripts from non-main targets in sidebars. LayoutTests: * inspector/worker/debugger-pause-expected.txt: Added. * inspector/worker/debugger-pause.html: Added. * inspector/worker/debugger-scripts-expected.txt: Added. * inspector/worker/debugger-scripts.html: Added. * inspector/worker/resources/worker-debugger-pause.js: Added. * inspector/worker/resources/worker-import-1.js: Added. * inspector/worker/resources/worker-scripts.js: Added. New tests for Debugger features in a Worker. * inspector/debugger/break-on-exception-throw-in-promise.html: * inspector/debugger/break-on-exception.html: * inspector/debugger/break-on-uncaught-exception.html: * inspector/debugger/evaluateOnCallFrame-CommandLineAPI.html: * inspector/debugger/pause-reason.html: * inspector/debugger/paused-scopes.html: * inspector/debugger/resources/log-pause-location.js: * inspector/debugger/stepping/stepInto.html: * inspector/debugger/stepping/stepOut.html: * inspector/debugger/stepping/stepOver.html: * inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html: * inspector/debugger/tail-deleted-frames-from-vm-entry.html: * inspector/debugger/tail-deleted-frames-this-value.html: * inspector/debugger/tail-deleted-frames.html: * inspector/debugger/tail-recursion.html: Most debugger data moved from DebuggerManager into DebuggerData for a target. Update tests that access such data like pauseReason / pauseData / callFrames. Canonical link: https://commits.webkit.org/182063@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208304 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 21:51:36 +00:00
let callFrame = callFrames[i];
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
InspectorTest.assert(callFrame.functionName === "recurse");
let topScope = callFrame.scopeChain[0];
if (i > 0)
InspectorTest.assert(callFrame.isTailDeleted);
else
InspectorTest.assert(!callFrame.isTailDeleted);
topScope.objects[0].getPropertyDescriptors(function(properties) {
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
let found = false;
for (let propertyDescriptor of properties) {
if (propertyDescriptor.name === 'i') {
found = true;
InspectorTest.log("Looking at frame number: " + i);
Web Inspector: Include RuntimeAgent in Workers - evaluate in Worker context https://bugs.webkit.org/show_bug.cgi?id=163835 <rdar://problem/28901465> Reviewed by Brian Burg. Source/WebCore: Tests: inspector/unit-tests/target-manager.html inspector/worker/runtime-basic.html * CMakeLists.txt: * WebCore.xcodeproj/project.pbxproj: * inspector/InspectorAllInOne.cpp: New file. * inspector/InspectorWebAgentBase.h: (WebCore::WorkerAgentContext::WorkerAgentContext): New agent context creation struct for Workers. * inspector/WorkerInspectorController.cpp: (WebCore::WorkerInspectorController::WorkerInspectorController): Create a RuntimeAgent for Workers. * inspector/WorkerRuntimeAgent.cpp: Added. (WebCore::WorkerRuntimeAgent::WorkerRuntimeAgent): (WebCore::WorkerRuntimeAgent::didCreateFrontendAndBackend): (WebCore::WorkerRuntimeAgent::willDestroyFrontendAndBackend): (WebCore::WorkerRuntimeAgent::injectedScriptForEval): * inspector/WorkerRuntimeAgent.h: Added. Workers currently only ever have a single execution context. Source/WebInspectorUI: This introduces the idea that the frontend may communication with multiple backend "Targets" which each have their own set of Agents. - WebInspector.Target - has its own list of Agents - has a InspectorBackend.Connection to communicate with the backend - WebInspector.mainTarget - always exists and represents the thing we are debugging (Page or JSContext) - WebInspector.targets / WebInspector.targetManager - management of all Targets - create new Targets for Workers This also slowly introduces the concept that Model objects may be tied to a specific Target: - WebInspector.RemoteObject - in order to evaluate JS and interact with this object we must know the target (Page or Worker) - when fetching PropertyDescriptors and other RemoteObjects we must continue to pass on the target Finally this makes the QuickConsole list Worker execution contexts in the context picker so that users can choose a Worker context and evaluate JavaScript in that context using the console. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Main.html: * UserInterface/Base/Main.js: (WebInspector.loaded): * UserInterface/Test.html: * UserInterface/Test/Test.js: (WebInspector.loaded): New files, strings, and managers. New global WebInspector.mainTarget. New convenience WebInspector.targets. * UserInterface/Protocol/Target.js: Added. (WebInspector.Target): (WebInspector.Target.prototype.get RuntimeAgent): (WebInspector.Target.prototype.get name): (WebInspector.Target.prototype.get type): (WebInspector.Target.prototype.get connection): (WebInspector.Target.prototype.get executionContext): (WebInspector.Target.prototype.get displayName): (WebInspector.Target.prototype._intializeMainTarget): (WebInspector.Target.prototype._initializeNonMainTarget): Target has some basic properties. * UserInterface/Controllers/TargetManager.js: (WebInspector.TargetManager): (WebInspector.TargetManager.prototype.get targets): (WebInspector.TargetManager.prototype.addTarget): (WebInspector.TargetManager.prototype.removeTarget): Holds the list of Targets and events when created / removed. Each target with a RuntimeAgent has an ExecutionContext. * UserInterface/Controllers/WorkerManager.js: (WebInspector.WorkerManager): (WebInspector.WorkerManager.prototype.workerCreated): (WebInspector.WorkerManager.prototype.workerTerminated): (WebInspector.WorkerManager.prototype.dispatchMessageFromWorker): Create / remove / dispatch on a Worker Target. * UserInterface/Protocol/InspectorBackend.js: (InspectorBackendClass): (InspectorBackendClass.prototype.registerCommand): (InspectorBackendClass.prototype.dispatch): (InspectorBackendClass.prototype.runAfterPendingDispatches): (InspectorBackendClass.prototype._agentForDomain): Keep the original implementations and just dispatch to the main connection. (InspectorBackend.Agent): (InspectorBackend.Agent.prototype.get connection): (InspectorBackend.Agent.prototype.set connection): (InspectorBackend.Agent.prototype.get dispatcher): We will share Agent implementations but just give new "copies" a different connection and dispatcher. (InspectorBackend.Command): (InspectorBackend.Command.create): (InspectorBackend.Command.prototype.invoke): (InspectorBackend.Command.prototype.supports): We continue to have a single Command instance on the Agent. However instead of using the hardcoded Agent on the Instance when evaluated as a function it uses the `this` object which should be an agent. This way: target1.RuntimeAgent.evaluate - `this` is target1 and we use the connection for that target target2.RuntimeAgent.evaluate - `this` is target2 and we use the connection for that target Unfortunately this breaks `RuntimeAgent.evaluate.invoke`. Currently this is solved by providing an extra parameter. In the case where we need to invoke on a particular agent we must provide the agent. target.RuntimeAgent.evaluate.invoke({options}, target.RuntimeAgent) This is unfortunate but only needed in a handful of places right now. (InspectorBackendClass.prototype._sendCommandToBackendWithCallback): Deleted. (InspectorBackendClass.prototype._sendCommandToBackendExpectingPromise): Deleted. (InspectorBackendClass.prototype._sendMessageToBackend): Deleted. (InspectorBackendClass.prototype._dispatchResponse): Deleted. (InspectorBackendClass.prototype._dispatchResponseToCallback): Deleted. (InspectorBackendClass.prototype._dispatchResponseToPromise): Deleted. (InspectorBackendClass.prototype._dispatchEvent): Deleted. (InspectorBackendClass.prototype._flushPendingScripts): Deleted. (InspectorBackend.Agent.prototype.get currentDispatchState): Deleted. (InspectorBackend.Command.prototype.deliverFailure): Deleted. * UserInterface/Protocol/Connection.js: Added. (InspectorBackend.Connection): (InspectorBackend.Connection.prototype.get target): (InspectorBackend.Connection.prototype.set target): (InspectorBackend.Connection.prototype.dispatch): (InspectorBackend.Connection.prototype.runAfterPendingDispatches): (InspectorBackend.Connection.prototype.sendMessageToBackend): (InspectorBackend.Connection.prototype._dispatchResponse): (InspectorBackend.Connection.prototype._dispatchResponseToCallback): (InspectorBackend.Connection.prototype._dispatchResponseToPromise): (InspectorBackend.Connection.prototype._dispatchEvent): (InspectorBackend.Connection.prototype._sendCommandToBackendWithCallback): (InspectorBackend.Connection.prototype._sendCommandToBackendExpectingPromise): (InspectorBackend.Connection.prototype._sendMessageToBackend): (InspectorBackend.Connection.prototype._flushPendingScripts): This extracts the Connection details into its own class. Although we make it appear as though a Target has a list of Agents, we actually have the Connection hold the list of Agents. Instead of cloning the entire Agent we just create a new object extended from the original Agent instance. This allows us to keep the same interface but just change the connection / dispatcher properties within the Agent. (InspectorBackend.MainConnection): (InspectorBackend.MainConnection.prototype.sendMessageToBackend): (InspectorBackend.WorkerConnection): (InspectorBackend.WorkerConnection.sendMessageToBackend): Two different kinds of connections. One for the Main connection and one for Workers. Currently the list of agents we expose on a Worker Target/Connection is hardcoded. * UserInterface/Models/ExecutionContext.js: (WebInspector.ExecutionContext): (WebInspector.ExecutionContext.prototype.get target): We may now have ExecutionContexts that mean a Page, Frames, and Workers. To do this we include the (target, executionContextId) tuple in this object. With this we have everything we need to evaluate JavaScript. * UserInterface/Controllers/RuntimeManager.js: (WebInspector.RuntimeManager): (WebInspector.RuntimeManager.prototype.get activeExecutionContext): (WebInspector.RuntimeManager.prototype.set activeExecutionContext): (WebInspector.RuntimeManager.prototype.get defaultExecutionContextIdentifier): Deleted. (WebInspector.RuntimeManager.prototype.set defaultExecutionContextIdentifier): Deleted. Update from contextId to a full ExecutionContext object. (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow.evalCallback): (WebInspector.RuntimeManager.prototype.evaluateInInspectedWindow): (WebInspector.RuntimeManager.prototype.saveResult): (WebInspector.RuntimeManager.prototype.getPropertiesForRemoteObject): (WebInspector.RuntimeManager.prototype._frameExecutionContextsCleared): * UserInterface/Controllers/FrameResourceManager.js: (WebInspector.FrameResourceManager.prototype.executionContextCreated): * UserInterface/Controllers/JavaScriptLogViewController.js: (WebInspector.JavaScriptLogViewController.prototype.consolePromptShouldCommitText): * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js: Anywhere that wants to use the "activeExecutionContext" must use the specific RuntimeAgent tied to that ExecutionContext's Target. * UserInterface/Models/PropertyDescriptor.js: (WebInspector.PropertyDescriptor.fromPayload): * UserInterface/Protocol/RemoteObject.js: (WebInspector.RemoteObject): (WebInspector.RemoteObject.createFakeRemoteObject): (WebInspector.RemoteObject.fromPrimitiveValue): (WebInspector.RemoteObject.fromPayload): (WebInspector.RemoteObject.prototype.getDisplayablePropertyDescriptors): (WebInspector.RemoteObject.prototype.deprecatedGetDisplayableProperties): (WebInspector.RemoteObject.prototype.setPropertyValue): (WebInspector.RemoteObject.prototype.getCollectionEntries): (WebInspector.RemoteObject.prototype.releaseWeakCollectionEntries): (WebInspector.RemoteObject.prototype.callFunction): (WebInspector.RemoteObject.prototype.callFunctionJSON): (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor.wrappedCallback): (WebInspector.RemoteObject.prototype.getOwnPropertyDescriptor): (WebInspector.RemoteObject.prototype.release): (WebInspector.RemoteObject.prototype._getPropertyDescriptors): (WebInspector.RemoteObject.prototype._getPropertyDescriptorsResolver): (WebInspector.RemoteObject.prototype._deprecatedGetProperties): RemoteObject and related Model Objects now must be tied to a specific Target, because we need to know which Target it belongs to in order to interact with it further. * UserInterface/Views/QuickConsole.js: (WebInspector.QuickConsole): (WebInspector.QuickConsole.prototype.get selectedExecutionContext): (WebInspector.QuickConsole.prototype.set selectedExecutionContext): (WebInspector.QuickConsole.prototype._executionContextPathComponentsToDisplay): (WebInspector.QuickConsole.prototype._rebuildExecutionContextPathComponents): (WebInspector.QuickConsole.prototype._framePageExecutionContextsChanged): (WebInspector.QuickConsole.prototype._frameExecutionContextsCleared): (WebInspector.QuickConsole.prototype._createExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._createExecutionContextPathComponentFromFrame): (WebInspector.QuickConsole.prototype._compareExecutionContextPathComponents): (WebInspector.QuickConsole.prototype._insertOtherExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._removeOtherExecutionContextPathComponent): (WebInspector.QuickConsole.prototype._insertExecutionContextPathComponentForFrame): (WebInspector.QuickConsole.prototype._removeExecutionContextPathComponentForFrame): (WebInspector.QuickConsole.prototype._targetAdded): (WebInspector.QuickConsole.prototype._targetRemoved): (WebInspector.QuickConsole.prototype._pathComponentSelected): (WebInspector.QuickConsole.prototype.get selectedExecutionContextIdentifier): Deleted. (WebInspector.QuickConsole.prototype.set selectedExecutionContextIdentifier): Deleted. (WebInspector.QuickConsole.prototype._defaultExecutionContextChanged): Deleted. Update the code from executionContextId to ExecutionContext objects. Update the picker with ExecutionContextPathComponent for Workers (new Targets). Generalize and cleanup the code to make it easier to follow. LayoutTests: * inspector/unit-tests/target-manager-expected.txt: Added. * inspector/unit-tests/target-manager.html: Added. Unit test for TargetManager and its events with Worker creation. * inspector/worker/resources/worker-1.js: * inspector/worker/runtime-basic-expected.txt: Added. * inspector/worker/runtime-basic.html: Added. Test comparing RuntimeAgent between Main target and Worker target. * inspector/runtime/change-execution-context-identifier-expected.txt: * inspector/runtime/change-execution-context-identifier.html: RuntimeManager has been updated to have a full ExecutionContext object containing a Target + ContextId instead of just a ContextId. * inspector/console/console-api-expected.txt: * inspector/console/console-api.html: * inspector/console/console-table-expected.txt: * inspector/console/console-table.html: * inspector/debugger/tail-deleted-frames-from-vm-entry.html: * inspector/debugger/tail-deleted-frames.html: * inspector/debugger/tail-recursion.html: * inspector/model/remote-object-expected.txt: * inspector/model/remote-object-weak-collection-expected.txt: * inspector/model/remote-object-weak-collection.html: * inspector/model/remote-object.html: * platform/mac/inspector/model/remote-object-expected.txt: Introduce a better JSON Filter for RemoteObject in more tests. It is important that we filter the _target, because otherwise JSON.stringify would throw an error about cycles. Canonical link: https://commits.webkit.org/181797@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208009 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-27 22:19:12 +00:00
InspectorTest.log(" variable 'i': " + JSON.stringify(propertyDescriptor.value, remoteObjectJSONFilter));
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
InspectorTest.assert(propertyDescriptor.value.type === 'number');
if (numBreakpointHits === 2 && i === 0)
InspectorTest.assert(propertyDescriptor.value.value === i + 1); // this tests the i++ inside tail-recurse.js
else
InspectorTest.assert(propertyDescriptor.value.value === i);
}
}
InspectorTest.assert(found);
});
}
WI.debuggerManager.resume();
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
});
WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Resumed, function(event) {
if (numBreakpointHits === 2) {
InspectorTest.log("Tests done");
InspectorTest.completeTest();
}
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
});
WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.ScriptAdded, function(event) {
Hook up ShadowChicken to the debugger to show tail deleted frames https://bugs.webkit.org/show_bug.cgi?id=156685 <rdar://problem/25770521> Reviewed by Filip Pizlo and Mark Lam and Joseph Pecoraro. Source/JavaScriptCore: The heart of this patch hooks up ShadowChicken to DebuggerCallFrame to allow the Web Inspector to display the ShadowChicken's shadow stack. This means the Web Inspector can now display tail deleted frames. To make this work, I made the necessary changes to ShadowChicken and DebuggerCallFrame to allow DebuggerCallFrame to keep the same API when representing both machine frames and tail deleted frames. - ShadowChicken prologue packets now log the current scope. Tail packets log the current scope, the 'this' value, the CodeBlock, and the CallSiteIndex. This allows the inspector to not only show the tail deleted frame, but also show exactly where the tail call happened (line and column numbers), with which scope it executed, and with which 'this' value. This patch also allows DebuggerCallFrame to execute console statements in a tail deleted frame. - I changed ShadowChicken's stack resizing algorithm. ShadowChicken now only keeps a maximum number of tail deleted frames in its shadow stack. It will happily represent all machine frames without limit. Right now, the maximum number of tail deleted frames I chose to keep alive is 128. We will keep frames alive starting from the top of the stack. This allows us to have a strong defense against runaway memory usage. We will only keep around at most 128 "shadow" frames that wouldn't have naturally been kept alive by the executing program. We can play around with this number if we find that 128 is either too many or too few frames. - DebuggerCallFrame is no longer a cheap class to create. When it is created, we will eagerly create the entire virtual debugger stack. So I modified the existing code to lazily create DebuggerCallFrames only when necessary. We used to eagerly create them at each op_debug statement even though we would just throw them away if we didn't hit a breakpoint. - A valid DebuggerCallFrame will always have a valid CallFrame* pointer into the stack. This pointer won't always refer to the logical frame that the DebuggerCallFrame represents because a DebuggerCallFrame can now represent a tail deleted frame. To do this, DebuggerCallFrame now has a ShadowChicken::Frame member variable. This allows DebuggerCallFrame to know when it represents a tail deleted frame and gives DebuggerCallFrame a mechanism to ask the tail deleted frame for interesting information (like its 'this' value, scope, CodeBlock, etc). A tail deleted frame's machine frame pointer will be the machine caller of the tail deleted frame (or the machine caller of the first of a series of consecutive tail calls). - I added a new flag to UnlinkedCodeBlock to indicate when it is compiled with debugging opcodes. I did this because ShadowChicken may read a JSScope from the machine stack. This is only safe if the machine CodeBlock was compiled with debugging opcodes. This is safer than asking if the CodeBlock's global object has an interactive debugger enabled because it's theoretically possible for the debugger to be enabled while code compiled without a debugger is still live on the stack. This field is also now used to indicate to the DFGGraph that the interactive debugger is enabled. - Finally, this patch adds a new field to the Inspector's CallFrame protocol object called 'isTailDeleted' to allow the Inspector to know when a CallFrame represents a tail deleted frame. * JavaScriptCore.xcodeproj/project.pbxproj: * bytecode/BytecodeList.json: * bytecode/BytecodeUseDef.h: (JSC::computeUsesForBytecodeOffset): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::dumpBytecode): (JSC::CodeBlock::findPC): (JSC::CodeBlock::bytecodeOffsetFromCallSiteIndex): * bytecode/CodeBlock.h: (JSC::CodeBlock::clearDebuggerRequests): (JSC::CodeBlock::wasCompiledWithDebuggingOpcodes): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::wasCompiledWithDebuggingOpcodes): (JSC::UnlinkedCodeBlock::finishCreation): (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::emitEnter): (JSC::BytecodeGenerator::emitLogShadowChickenPrologueIfNecessary): (JSC::BytecodeGenerator::emitLogShadowChickenTailIfNecessary): (JSC::BytecodeGenerator::emitCallDefineProperty): * debugger/Debugger.cpp: (JSC::DebuggerPausedScope::DebuggerPausedScope): (JSC::DebuggerPausedScope::~DebuggerPausedScope): (JSC::Debugger::didReachBreakpoint): (JSC::Debugger::currentDebuggerCallFrame): * debugger/Debugger.h: * debugger/DebuggerCallFrame.cpp: (JSC::LineAndColumnFunctor::operator()): (JSC::DebuggerCallFrame::create): (JSC::DebuggerCallFrame::DebuggerCallFrame): (JSC::DebuggerCallFrame::callerFrame): (JSC::DebuggerCallFrame::globalExec): (JSC::DebuggerCallFrame::vmEntryGlobalObject): (JSC::DebuggerCallFrame::sourceID): (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::scope): (JSC::DebuggerCallFrame::type): (JSC::DebuggerCallFrame::thisValue): (JSC::DebuggerCallFrame::evaluateWithScopeExtension): (JSC::DebuggerCallFrame::invalidate): (JSC::DebuggerCallFrame::currentPosition): (JSC::DebuggerCallFrame::positionForCallFrame): (JSC::DebuggerCallFrame::sourceIDForCallFrame): (JSC::FindCallerMidStackFunctor::FindCallerMidStackFunctor): Deleted. (JSC::FindCallerMidStackFunctor::operator()): Deleted. (JSC::FindCallerMidStackFunctor::getCallerFrame): Deleted. (JSC::DebuggerCallFrame::thisValueForCallFrame): Deleted. * debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::isValid): (JSC::DebuggerCallFrame::isTailDeleted): (JSC::DebuggerCallFrame::create): Deleted. (JSC::DebuggerCallFrame::exec): Deleted. * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::Graph): (JSC::DFG::Graph::~Graph): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addCallSite): (JSC::DFG::JITCompiler::emitStoreCodeOrigin): (JSC::DFG::JITCompiler::emitStoreCallSiteIndex): * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * ftl/FTLAbstractHeapRepository.h: * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenPrologue): (JSC::FTL::DFG::LowerDFGToB3::compileLogShadowChickenTail): (JSC::FTL::DFG::LowerDFGToB3::compileRecordRegExpCachedResult): (JSC::FTL::DFG::LowerDFGToB3::allocateJSArray): (JSC::FTL::DFG::LowerDFGToB3::ensureShadowChickenPacket): (JSC::FTL::DFG::LowerDFGToB3::setupShadowChickenPacket): Deleted. * inspector/InjectedScriptSource.js: (InjectedScript.CallFrameProxy): * inspector/JSJavaScriptCallFrame.cpp: (Inspector::JSJavaScriptCallFrame::thisObject): (Inspector::JSJavaScriptCallFrame::isTailDeleted): (Inspector::JSJavaScriptCallFrame::type): * inspector/JSJavaScriptCallFrame.h: * inspector/JSJavaScriptCallFramePrototype.cpp: (Inspector::JSJavaScriptCallFramePrototype::finishCreation): (Inspector::jsJavaScriptCallFramePrototypeFunctionEvaluateWithScopeExtension): (Inspector::jsJavaScriptCallFrameAttributeType): (Inspector::jsJavaScriptCallFrameIsTailDeleted): * inspector/JavaScriptCallFrame.h: (Inspector::JavaScriptCallFrame::type): (Inspector::JavaScriptCallFrame::scopeChain): (Inspector::JavaScriptCallFrame::vmEntryGlobalObject): (Inspector::JavaScriptCallFrame::isTailDeleted): (Inspector::JavaScriptCallFrame::thisValue): (Inspector::JavaScriptCallFrame::evaluateWithScopeExtension): * inspector/ScriptDebugServer.cpp: (Inspector::ScriptDebugServer::evaluateBreakpointAction): * inspector/protocol/Debugger.json: * interpreter/ShadowChicken.cpp: (JSC::ShadowChicken::update): (JSC::ShadowChicken::visitChildren): (JSC::ShadowChicken::reset): * interpreter/ShadowChicken.h: (JSC::ShadowChicken::Packet::throwMarker): (JSC::ShadowChicken::Packet::prologue): (JSC::ShadowChicken::Packet::tail): (JSC::ShadowChicken::Frame::Frame): (JSC::ShadowChicken::Frame::operator==): * jit/CCallHelpers.cpp: (JSC::CCallHelpers::logShadowChickenProloguePacket): (JSC::CCallHelpers::logShadowChickenTailPacket): (JSC::CCallHelpers::ensureShadowChickenPacket): (JSC::CCallHelpers::setupShadowChickenPacket): Deleted. * jit/CCallHelpers.h: * jit/JITOpcodes.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): (JSC::JIT::emit_op_get_enumerable_length): (JSC::JIT::emit_op_resume): * jit/JITOpcodes32_64.cpp: (JSC::JIT::emit_op_profile_type): (JSC::JIT::emit_op_log_shadow_chicken_prologue): (JSC::JIT::emit_op_log_shadow_chicken_tail): * jit/RegisterSet.cpp: (JSC::RegisterSet::webAssemblyCalleeSaveRegisters): (JSC::RegisterSet::argumentGPRS): (JSC::RegisterSet::registersToNotSaveForJSCall): * jit/RegisterSet.h: * llint/LLIntData.cpp: (JSC::LLInt::Data::performAssertions): * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * runtime/CodeCache.cpp: (JSC::CodeCache::getGlobalCodeBlock): * runtime/Options.h: * tests/stress/shadow-chicken-enabled.js: (test5a.foo): (test5a): (test5b.foo): (test5b): (test6.foo): (test6): Source/WebCore: Tests: inspector/debugger/tail-deleted-frames-this-value.html inspector/debugger/tail-deleted-frames.html inspector/debugger/tail-recursion.html * ForwardingHeaders/interpreter/ShadowChicken.h: Added. Source/WebInspectorUI: This patch makes the WebInspector display tail deleted frames. We show tail deleted frames with a gray [f] instead of a green [f]. We also put text in the tooltip to indicate that the frame is tail deleted. Other than that, tail deleted frames behave like normal frames. You can evaluate in them, inspect their scope, etc. * Localizations/en.lproj/localizedStrings.js: * UserInterface/Images/TailDeletedFunction.svg: Added. * UserInterface/Images/gtk/TailDeletedFunction.svg: Added. * UserInterface/Models/CallFrame.js: * UserInterface/Views/CallFrameIcons.css: * UserInterface/Views/CallFrameTreeElement.js: * UserInterface/Views/CallFrameView.js: LayoutTests: * inspector/debugger/resources/tail-deleted-frames-this-value.js: Added. (a): (b): * inspector/debugger/resources/tail-deleted-frames.js: Added. (a): (b): (c): (startABC): * inspector/debugger/resources/tail-recursion.js: Added. (recurse): (startRecurse): * inspector/debugger/tail-deleted-frames-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value-expected.txt: Added. * inspector/debugger/tail-deleted-frames-this-value.html: Added. * inspector/debugger/tail-deleted-frames.html: Added. * inspector/debugger/tail-recursion-expected.txt: Added. * inspector/debugger/tail-recursion.html: Added. Canonical link: https://commits.webkit.org/175902@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@200981 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-05-16 23:31:39 +00:00
eventScriptObject = event.data.script;
if (/tail-recursion\.js$/.test(eventScriptObject.url)) {
scriptObject = eventScriptObject;
startTest();
return;
}
});
InspectorTest.reloadPage();
}
</script>
</head>
<body onload="runTest()">
<p>Testing that we keep around tail deleted frames in the inspector. </p>
</body>
</html>