Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Web Inspector: Debugger: symbolic breakpoints should work with native…
… functions https://bugs.webkit.org/show_bug.cgi?id=243716 <rdar://problem/98705760> Reviewed by Yusuke Suzuki. * Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h: * Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::InspectorDebuggerAgent::internalDisable): (Inspector::functionName): (Inspector::ReplacedThunk::~ReplacedThunk): Added. (Inspector::ReplacedThunk::operator==): Added. (Inspector::replacedThunks()): Added. (Inspector::InspectorDebuggerAgent::addSymbolicBreakpoint): (Inspector::InspectorDebuggerAgent::removeSymbolicBreakpoint): (Inspector::InspectorDebuggerAgent::didCreateNativeExecutable): Added. (Inspector::InspectorDebuggerAgent::willCallNativeExecutable): Added. (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState): When creating a new symbolic breakpoint (i.e. `addSymbolicBreakpoint`), walk the entire heap for all `NativeExecutable`, instrumenting any that are newly matched (i.e. it had no other matching symbolic breakpoints) as though it was just created by replacing the "call" and "construct" thunks with "debugger" copies (see below). Do the same for any newly created `NativeExecutable`. When any `NativeExecutable` is about to "call" or "construct", check first if there are any matching symbolic breakpoints, pausing immediately if so. This ensures we pause before invoking the `NativeExecutable` (whereas non-native symbolic breakpoints will pause on the first expression inside the JS function). When removing symbolic breakpoints (or closing Web Inspector), undo any replaced thunks. * Source/JavaScriptCore/debugger/Debugger.h: (JSC::Debugger::Observer::didCreateNativeExecutable): Added. (JSC::Debugger::Observer::willCallNativeExecutable): Added. (JSC::Debugger::doneProcessingDebuggerEvents const): Deleted. * Source/JavaScriptCore/debugger/Debugger.cpp: (JSC::Debugger::Debugger): (JSC::Debugger::~Debugger): (JSC::Debugger::didCreateNativeExecutable): Added. (JSC::Debugger::willCallNativeExecutable): Added. (JSC::Debugger::canDispatchFunctionToObservers const): (JSC::Debugger::dispatchFunctionToObservers): * Source/JavaScriptCore/runtime/VM.h: * Source/JavaScriptCore/runtime/VM.cpp: (JSC::VM::addDebugger): Added. (JSC::VM::removeDebugger): Added. (JSC::VM::forEachDebugger): Added. Add piping to allow other JSC objects to talk to `InspectorDebuggerAgent` without having to know about it directly. * Source/JavaScriptCore/jit/JITThunks.h: * Source/JavaScriptCore/jit/JITThunks.cpp: (JSC::JITThunks::ctiNativeCallWithDebuggerHook): Added. (JSC::JITThunks::ctiNativeConstructWithDebuggerHook): Added. * Source/JavaScriptCore/jit/ThunkGenerators.h: * Source/JavaScriptCore/jit/ThunkGenerators.cpp: (JSC::nativeForGenerator): (JSC::nativeCallWithDebuggerHookGenerator): Added. (JSC::nativeConstructWithDebuggerHookGenerator): Added. * Source/JavaScriptCore/jit/JITOperations.h: * Source/JavaScriptCore/jit/JITOperations.cpp: (JSC::operationDebuggerWillCallNativeExecutable): Added. Create "debugger" copies of the "call" and "construct" thunks that call a new JIT operation to notify the `InspectorDebuggerAgent` before invoking the native code so that it can pause if it has matching symbolic breakpoints. * Source/JavaScriptCore/jit/JITCode.h: (JSC::JITCode::canSwapCodeRefForDebugger const): Added. (JSC::NativeJITCode::canSwapCodeRefForDebugger const): Added. * Source/JavaScriptCore/jit/JITCode.cpp: (JSC::JITCode::swapCodeRefForDebugger): Added. (JSC::JITCodeWithCodeRef::swapCodeRefForDebugger): Added. * Source/JavaScriptCore/runtime/ExecutableBase.h: (JSC::ExecutableBase::generatedJITCodeWithArityCheckForCall const): Added. (JSC::ExecutableBase::generatedJITCodeWithArityCheckForConstruct const): Added. (JSC::ExecutableBase::generatedJITCodeWithArityCheckFor const): Added. (JSC::ExecutableBase::swapGeneratedJITCodeWithArityCheckForDebugger): Added. (JSC::ExecutableBase::swapGeneratedJITCodeForCallWithArityCheckForDebugger): Added. (JSC::ExecutableBase::swapGeneratedJITCodeForConstructWithArityCheckForDebugger): Added. Add utility functions to allow the `InspectorDebuggerAgent` to swap JIT code without having to regenerate the entire object. * Source/JavaScriptCore/runtime/NativeExecutable.cpp: (JSC::NativeExecutable::create): Since `NativeExeutable` are shared for all `JSGlobalObject` in a `VM`, iterate the global list of all `Debugger` to find all matching the `VM`, informing each about this new `NativeExecutable`. Each `InspectorDebuggerAgent` will similarly pull from a global list of all replaced thunks so as to avoid replacing the thunks of a single `NativeExecutable` more than once. * Source/JavaScriptCore/inspector/JSGlobalObjectDebugger.cpp: (Inspector::JSGlobalObjectDebugger::runEventLoopWhilePaused): * Source/WebCore/inspector/PageDebugger.cpp: (WebCore::PageDebugger::runEventLoopWhilePausedInternal): * Source/WebCore/inspector/WorkerDebugger.cpp: (WebCore::WorkerDebugger::runEventLoopWhilePaused): I'm not entirely sure what's going on here, but all the local testing I did had problems where `doneProcessingDebuggerEvents()` would return `false` even though `m_doneProcessingDebuggerEvents` had been set to `true`. Using `std::atomic<bool>` didn't work either (this was more of a hailmary than anything). Directly using the variable resolved this. * Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js: (WI.DebuggerManager.prototype._setSymbolicBreakpoint): (WI.DebuggerManager.prototype._handleSymbolicBreakpointActionsChanged): Drive-by: Use `this` instead of `WI.debuggerManager` since we're already inside `WI.DebuggerManager`. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-exact-case-insensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-exact-case-insensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-exact-case-sensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-exact-case-sensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-regex-case-insensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-regex-case-insensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-regex-case-sensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-dom-regex-case-sensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-exact-case-insensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-exact-case-insensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-exact-case-sensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-exact-case-sensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-regex-case-insensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-regex-case-insensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-regex-case-sensitive-expected.txt: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-native-js-regex-case-sensitive.html: Added. * LayoutTests/inspector/debugger/symbolic-breakpoint-exact-case-insensitive.html: * LayoutTests/inspector/debugger/symbolic-breakpoint-exact-case-sensitive.html: * LayoutTests/inspector/debugger/symbolic-breakpoint-regex-case-insensitive.html: * LayoutTests/inspector/debugger/symbolic-breakpoint-regex-case-sensitive.html: Drive-by: Actually add the `WI.SymbolicBreakpoint` to the `WI.DebuggerManager` instead of relying on the event listeners added to `WI.SymbolicBreakpoint` (as opposed to a specific instance). Canonical link: https://commits.webkit.org/253791@main
- Loading branch information