From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- .../JavaScriptCore/inspector/ScriptDebugServer.cpp | 259 +++++++++++---------- 1 file changed, 139 insertions(+), 120 deletions(-) (limited to 'Source/JavaScriptCore/inspector/ScriptDebugServer.cpp') diff --git a/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp b/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp index b1151cf7f..84cefdf70 100644 --- a/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp +++ b/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -32,25 +32,22 @@ #include "ScriptDebugServer.h" #include "DebuggerCallFrame.h" +#include "DebuggerScope.h" +#include "Exception.h" +#include "JSCInlines.h" #include "JSJavaScriptCallFrame.h" -#include "JSLock.h" #include "JavaScriptCallFrame.h" #include "ScriptValue.h" #include "SourceProvider.h" -#include #include -#include -#include +#include using namespace JSC; -using namespace Inspector; namespace Inspector { -ScriptDebugServer::ScriptDebugServer(bool isInWorkerThread) - : Debugger(isInWorkerThread) - , m_doneProcessingDebuggerEvents(true) - , m_callingListeners(false) +ScriptDebugServer::ScriptDebugServer(VM& vm) + : Debugger(vm) { } @@ -58,62 +55,67 @@ ScriptDebugServer::~ScriptDebugServer() { } -JSC::BreakpointID ScriptDebugServer::setBreakpoint(JSC::SourceID sourceID, const ScriptBreakpoint& scriptBreakpoint, unsigned* actualLineNumber, unsigned* actualColumnNumber) +void ScriptDebugServer::setBreakpointActions(BreakpointID id, const ScriptBreakpoint& scriptBreakpoint) { - if (!sourceID) - return JSC::noBreakpointID; - - JSC::Breakpoint breakpoint(sourceID, scriptBreakpoint.lineNumber, scriptBreakpoint.columnNumber, scriptBreakpoint.condition, scriptBreakpoint.autoContinue); - JSC::BreakpointID id = Debugger::setBreakpoint(breakpoint, *actualLineNumber, *actualColumnNumber); - if (id != JSC::noBreakpointID && !scriptBreakpoint.actions.isEmpty()) { -#ifndef NDEBUG - BreakpointIDToActionsMap::iterator it = m_breakpointIDToActions.find(id); - ASSERT(it == m_breakpointIDToActions.end()); -#endif - const Vector &actions = scriptBreakpoint.actions; - m_breakpointIDToActions.set(id, actions); - } - return id; + ASSERT(id != noBreakpointID); + ASSERT(!m_breakpointIDToActions.contains(id)); + + m_breakpointIDToActions.set(id, scriptBreakpoint.actions); } -void ScriptDebugServer::removeBreakpoint(JSC::BreakpointID id) +void ScriptDebugServer::removeBreakpointActions(BreakpointID id) { - ASSERT(id != JSC::noBreakpointID); - BreakpointIDToActionsMap::iterator it = m_breakpointIDToActions.find(id); - if (it != m_breakpointIDToActions.end()) - m_breakpointIDToActions.remove(it); + ASSERT(id != noBreakpointID); - Debugger::removeBreakpoint(id); + m_breakpointIDToActions.remove(id); +} + +const BreakpointActions& ScriptDebugServer::getActionsForBreakpoint(BreakpointID id) +{ + ASSERT(id != noBreakpointID); + + auto entry = m_breakpointIDToActions.find(id); + if (entry != m_breakpointIDToActions.end()) + return entry->value; + + static NeverDestroyed emptyActionVector = BreakpointActions(); + return emptyActionVector; +} + +void ScriptDebugServer::clearBreakpointActions() +{ + m_breakpointIDToActions.clear(); } bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& breakpointAction) { - DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame(); + DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame(); switch (breakpointAction.type) { case ScriptBreakpointActionTypeLog: { - dispatchBreakpointActionLog(debuggerCallFrame->exec(), breakpointAction.data); + dispatchBreakpointActionLog(debuggerCallFrame.globalExec(), breakpointAction.data); break; } case ScriptBreakpointActionTypeEvaluate: { - JSValue exception; - debuggerCallFrame->evaluate(breakpointAction.data, exception); + NakedPtr exception; + JSObject* scopeExtensionObject = nullptr; + debuggerCallFrame.evaluateWithScopeExtension(breakpointAction.data, scopeExtensionObject, exception); if (exception) - reportException(debuggerCallFrame->exec(), exception); + reportException(debuggerCallFrame.globalExec(), exception); break; } case ScriptBreakpointActionTypeSound: - dispatchBreakpointActionSound(debuggerCallFrame->exec()); + dispatchBreakpointActionSound(debuggerCallFrame.globalExec(), breakpointAction.identifier); break; case ScriptBreakpointActionTypeProbe: { - JSValue exception; - JSValue result = debuggerCallFrame->evaluate(breakpointAction.data, exception); + NakedPtr exception; + JSObject* scopeExtensionObject = nullptr; + JSValue result = debuggerCallFrame.evaluateWithScopeExtension(breakpointAction.data, scopeExtensionObject, exception); + JSC::ExecState* exec = debuggerCallFrame.globalExec(); if (exception) - reportException(debuggerCallFrame->exec(), exception); - - JSC::ExecState* state = debuggerCallFrame->scope()->globalObject()->globalExec(); - Deprecated::ScriptValue wrappedResult = Deprecated::ScriptValue(state->vm(), exception ? exception : result); - dispatchDidSampleProbe(state, breakpointAction.identifier, wrappedResult); + reportException(exec, exception); + + dispatchBreakpointActionProbe(exec, breakpointAction, exception ? exception->value() : result); break; } default: @@ -123,21 +125,14 @@ bool ScriptDebugServer::evaluateBreakpointAction(const ScriptBreakpointAction& b return true; } -void ScriptDebugServer::clearBreakpoints() -{ - Debugger::clearBreakpoints(); - m_breakpointIDToActions.clear(); -} - void ScriptDebugServer::dispatchDidPause(ScriptDebugListener* listener) { ASSERT(isPaused()); - DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame(); - JSGlobalObject* globalObject = debuggerCallFrame->scope()->globalObject(); - JSC::ExecState* state = globalObject->globalExec(); - RefPtr javaScriptCallFrame = JavaScriptCallFrame::create(debuggerCallFrame); - JSValue jsCallFrame = toJS(state, globalObject, javaScriptCallFrame.get()); - listener->didPause(state, Deprecated::ScriptValue(state->vm(), jsCallFrame), Deprecated::ScriptValue()); + DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame(); + JSGlobalObject* globalObject = debuggerCallFrame.scope()->globalObject(); + JSC::ExecState& state = *globalObject->globalExec(); + JSValue jsCallFrame = toJS(&state, globalObject, JavaScriptCallFrame::create(debuggerCallFrame).ptr()); + listener->didPause(state, jsCallFrame, exceptionOrCaughtValue(&state)); } void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const String& message) @@ -145,53 +140,49 @@ void ScriptDebugServer::dispatchBreakpointActionLog(ExecState* exec, const Strin if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + if (m_listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); - TemporaryChange change(m_callingListeners, true); + SetForScope change(m_callingListeners, true); Vector listenersCopy; - copyToVector(*listeners, listenersCopy); - for (auto listener : listenersCopy) - listener->breakpointActionLog(exec, message); + copyToVector(m_listeners, listenersCopy); + for (auto* listener : listenersCopy) + listener->breakpointActionLog(*exec, message); } -void ScriptDebugServer::dispatchBreakpointActionSound(ExecState* exec) +void ScriptDebugServer::dispatchBreakpointActionSound(ExecState*, int breakpointActionIdentifier) { if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + if (m_listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); - TemporaryChange change(m_callingListeners, true); + SetForScope change(m_callingListeners, true); Vector listenersCopy; - copyToVector(*listeners, listenersCopy); - for (auto listener : listenersCopy) - listener->breakpointActionSound(); + copyToVector(m_listeners, listenersCopy); + for (auto* listener : listenersCopy) + listener->breakpointActionSound(breakpointActionIdentifier); } -void ScriptDebugServer::dispatchDidSampleProbe(ExecState* exec, int identifier, const Deprecated::ScriptValue& sample) +void ScriptDebugServer::dispatchBreakpointActionProbe(ExecState* exec, const ScriptBreakpointAction& action, JSC::JSValue sampleValue) { if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + if (m_listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); - TemporaryChange change(m_callingListeners, true); + SetForScope change(m_callingListeners, true); + + unsigned sampleId = m_nextProbeSampleId++; Vector listenersCopy; - copyToVector(*listeners, listenersCopy); - for (auto listener : listenersCopy) - listener->didSampleProbe(exec, identifier, m_hitCount, sample); + copyToVector(m_listeners, listenersCopy); + for (auto* listener : listenersCopy) + listener->breakpointActionProbe(*exec, action, m_currentProbeBatchId, sampleId, sampleValue); } void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener) @@ -203,12 +194,16 @@ void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, Sou { JSC::SourceID sourceID = sourceProvider->asID(); + // FIXME: Web Inspector: Simplify ScriptDebugListener::Script to use SourceProvider ScriptDebugListener::Script script; + script.sourceProvider = sourceProvider; script.url = sourceProvider->url(); - script.source = sourceProvider->source(); + script.source = sourceProvider->source().toString(); script.startLine = sourceProvider->startPosition().m_line.zeroBasedInt(); script.startColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); script.isContentScript = isContentScript; + script.sourceURL = sourceProvider->sourceURL(); + script.sourceMappingURL = sourceProvider->sourceMappingURL(); int sourceLength = script.source.length(); int lineCount = 1; @@ -235,7 +230,7 @@ void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, Sou void ScriptDebugServer::dispatchFailedToParseSource(const ListenerSet& listeners, SourceProvider* sourceProvider, int errorLine, const String& errorMessage) { String url = sourceProvider->url(); - const String& data = sourceProvider->source(); + String data = sourceProvider->source().toString(); int firstLine = sourceProvider->startPosition().m_line.oneBasedInt(); Vector copy; @@ -249,18 +244,29 @@ void ScriptDebugServer::sourceParsed(ExecState* exec, SourceProvider* sourceProv if (m_callingListeners) return; - ListenerSet* listeners = getListenersForGlobalObject(exec->lexicalGlobalObject()); - if (!listeners) + if (m_listeners.isEmpty()) return; - ASSERT(!listeners->isEmpty()); - TemporaryChange change(m_callingListeners, true); + SetForScope change(m_callingListeners, true); bool isError = errorLine != -1; if (isError) - dispatchFailedToParseSource(*listeners, sourceProvider, errorLine, errorMessage); + dispatchFailedToParseSource(m_listeners, sourceProvider, errorLine, errorMessage); else - dispatchDidParseSource(*listeners, sourceProvider, isContentScript(exec)); + dispatchDidParseSource(m_listeners, sourceProvider, isContentScript(exec)); +} + +void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback) +{ + if (m_callingListeners) + return; + + if (m_listeners.isEmpty()) + return; + + SetForScope change(m_callingListeners, true); + + dispatchFunctionToListeners(m_listeners, callback); } void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback) @@ -271,68 +277,81 @@ void ScriptDebugServer::dispatchFunctionToListeners(const ListenerSet& listeners (this->*callback)(copy[i]); } -void ScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, JSGlobalObject* globalObject) -{ - if (m_callingListeners) - return; - - TemporaryChange change(m_callingListeners, true); - - if (ListenerSet* listeners = getListenersForGlobalObject(globalObject)) { - ASSERT(!listeners->isEmpty()); - dispatchFunctionToListeners(*listeners, callback); - } -} - void ScriptDebugServer::notifyDoneProcessingDebuggerEvents() { m_doneProcessingDebuggerEvents = true; } -bool ScriptDebugServer::needPauseHandling(JSGlobalObject* globalObject) +void ScriptDebugServer::handleBreakpointHit(JSC::JSGlobalObject* globalObject, const JSC::Breakpoint& breakpoint) { - return !!getListenersForGlobalObject(globalObject); -} + ASSERT(isAttached(globalObject)); -void ScriptDebugServer::handleBreakpointHit(const JSC::Breakpoint& breakpoint) -{ - m_hitCount++; - BreakpointIDToActionsMap::iterator it = m_breakpointIDToActions.find(breakpoint.id); - if (it != m_breakpointIDToActions.end()) { - BreakpointActions& actions = it->value; + m_currentProbeBatchId++; + + auto entry = m_breakpointIDToActions.find(breakpoint.id); + if (entry != m_breakpointIDToActions.end()) { + BreakpointActions actions = entry->value; for (size_t i = 0; i < actions.size(); ++i) { if (!evaluateBreakpointAction(actions[i])) return; + if (!isAttached(globalObject)) + return; } } } -void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::JSValue exception) const +void ScriptDebugServer::handleExceptionInBreakpointCondition(JSC::ExecState* exec, JSC::Exception* exception) const { reportException(exec, exception); } -void ScriptDebugServer::handlePause(Debugger::ReasonForPause, JSGlobalObject* vmEntryGlobalObject) +void ScriptDebugServer::handlePause(JSGlobalObject* vmEntryGlobalObject, Debugger::ReasonForPause) { - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause, vmEntryGlobalObject); + dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause); didPause(vmEntryGlobalObject); m_doneProcessingDebuggerEvents = false; runEventLoopWhilePaused(); didContinue(vmEntryGlobalObject); - dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue, vmEntryGlobalObject); + dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue); } -const Vector& ScriptDebugServer::getActionsForBreakpoint(JSC::BreakpointID breakpointID) +void ScriptDebugServer::addListener(ScriptDebugListener* listener) { - ASSERT(breakpointID != JSC::noBreakpointID); + ASSERT(listener); - if (m_breakpointIDToActions.contains(breakpointID)) - return m_breakpointIDToActions.find(breakpointID)->value; - - static NeverDestroyed> emptyActionVector = Vector(); - return emptyActionVector; + bool wasEmpty = m_listeners.isEmpty(); + m_listeners.add(listener); + + // First listener. Attach the debugger. + if (wasEmpty) + attachDebugger(); +} + +void ScriptDebugServer::removeListener(ScriptDebugListener* listener, bool isBeingDestroyed) +{ + ASSERT(listener); + + m_listeners.remove(listener); + + // Last listener. Detach the debugger. + if (m_listeners.isEmpty()) + detachDebugger(isBeingDestroyed); +} + +JSC::JSValue ScriptDebugServer::exceptionOrCaughtValue(JSC::ExecState* state) +{ + if (reasonForPause() == PausedForException) + return currentException(); + + for (RefPtr frame = ¤tDebuggerCallFrame(); frame; frame = frame->callerFrame()) { + DebuggerScope& scope = *frame->scope(); + if (scope.isCatchScope()) + return scope.caughtValue(state); + } + + return { }; } } // namespace Inspector -- cgit v1.2.1