Unreviewed, rolling out r103405.
[WebKit-https.git] / Source / WebCore / inspector / InspectorDebuggerAgent.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010-2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "InspectorDebuggerAgent.h"
32
33 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
34 #include "ContentSearchUtils.h"
35 #include "InjectedScript.h"
36 #include "InjectedScriptManager.h"
37 #include "InspectorFrontend.h"
38 #include "InspectorState.h"
39 #include "InspectorValues.h"
40 #include "InstrumentingAgents.h"
41 #include "RegularExpression.h"
42 #include "ScriptDebugServer.h"
43 #include "ScriptObject.h"
44 #include <wtf/text/WTFString.h>
45
46 namespace WebCore {
47
48 namespace DebuggerAgentState {
49 static const char debuggerEnabled[] = "debuggerEnabled";
50 static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
51 };
52
53 const char* InspectorDebuggerAgent::backtraceObjectGroup = "backtrace-object-group";
54
55 InspectorDebuggerAgent::InspectorDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
56     : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger", instrumentingAgents, inspectorState)
57     , m_injectedScriptManager(injectedScriptManager)
58     , m_frontend(0)
59     , m_pausedScriptState(0)
60     , m_javaScriptPauseScheduled(false)
61     , m_listener(0)
62 {
63     // FIXME: make breakReason optional so that there was no need to init it with "other".
64     clearBreakDetails();
65 }
66
67 InspectorDebuggerAgent::~InspectorDebuggerAgent()
68 {
69     ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent());
70 }
71
72 void InspectorDebuggerAgent::enable()
73 {
74     m_instrumentingAgents->setInspectorDebuggerAgent(this);
75
76     // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
77     scriptDebugServer().setBreakpointsActivated(true);
78     startListeningScriptDebugServer();
79
80     if (m_listener)
81         m_listener->debuggerWasEnabled();
82 }
83
84 void InspectorDebuggerAgent::disable()
85 {
86     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, InspectorObject::create());
87     m_instrumentingAgents->setInspectorDebuggerAgent(0);
88
89     stopListeningScriptDebugServer();
90     scriptDebugServer().clearBreakpoints();
91     clear();
92
93     if (m_listener)
94         m_listener->debuggerWasDisabled();
95 }
96
97 bool InspectorDebuggerAgent::enabled()
98 {
99     return m_state->getBoolean(DebuggerAgentState::debuggerEnabled);
100 }
101
102 void InspectorDebuggerAgent::causesRecompilation(ErrorString*, bool* result)
103 {
104     *result = scriptDebugServer().causesRecompilation();
105 }
106
107 void InspectorDebuggerAgent::canSetScriptSource(ErrorString*, bool* result)
108 {
109     *result = scriptDebugServer().canSetScriptSource();
110 }
111
112 void InspectorDebuggerAgent::supportsNativeBreakpoints(ErrorString*, bool* result)
113 {
114     *result = scriptDebugServer().supportsNativeBreakpoints();
115 }
116
117 void InspectorDebuggerAgent::enable(ErrorString*)
118 {
119     if (enabled())
120         return;
121
122     enable();
123     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
124
125     ASSERT(m_frontend);
126 }
127
128 void InspectorDebuggerAgent::disable(ErrorString*)
129 {
130     if (!enabled())
131         return;
132
133     disable();
134     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
135 }
136
137 void InspectorDebuggerAgent::restore()
138 {
139     if (enabled()) {
140         m_frontend->globalObjectCleared();
141         enable();
142     }
143 }
144
145 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend)
146 {
147     m_frontend = frontend->debugger();
148 }
149
150 void InspectorDebuggerAgent::clearFrontend()
151 {
152     m_frontend = 0;
153
154     if (!enabled())
155         return;
156
157     disable();
158
159     // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only
160     // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true,
161     // but after front-end re-open it will still be false.
162     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
163 }
164
165 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active)
166 {
167     if (active)
168         scriptDebugServer().activateBreakpoints();
169     else
170         scriptDebugServer().deactivateBreakpoints();
171 }
172
173 void InspectorDebuggerAgent::didClearMainFrameWindowObject()
174 {
175     m_scripts.clear();
176     m_breakpointIdToDebugServerBreakpointIds.clear();
177     if (m_frontend)
178         m_frontend->globalObjectCleared();
179 }
180
181 static PassRefPtr<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex)
182 {
183     RefPtr<InspectorObject> breakpointObject = InspectorObject::create();
184     breakpointObject->setString("url", url);
185     breakpointObject->setNumber("lineNumber", lineNumber);
186     breakpointObject->setNumber("columnNumber", columnNumber);
187     breakpointObject->setString("condition", condition);
188     breakpointObject->setBoolean("isRegex", isRegex);
189     return breakpointObject;
190 }
191
192 static bool matches(const String& url, const String& pattern, bool isRegex)
193 {
194     if (isRegex) {
195         RegularExpression regex(pattern, TextCaseSensitive);
196         return regex.match(url) != -1;
197     }
198     return url == pattern;
199 }
200
201 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, String* outBreakpointId, RefPtr<InspectorArray>& locations)
202 {
203     if (!optionalURL == !optionalURLRegex) {
204         *errorString = "Either url or urlRegex must be specified.";
205         return;
206     }
207
208     String url = optionalURL ? *optionalURL : *optionalURLRegex;
209     int columnNumber = optionalColumnNumber ? *optionalColumnNumber : 0;
210     String condition = optionalCondition ? *optionalCondition : "";
211     bool isRegex = optionalURLRegex;
212
213     String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
214     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
215     if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) {
216         *errorString = "Breakpoint at specified location already exists.";
217         return;
218     }
219
220     breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex));
221     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
222
223     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
224     for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) {
225         if (!matches(it->second.url, url, isRegex))
226             continue;
227         RefPtr<InspectorObject> location = resolveBreakpoint(breakpointId, it->first, breakpoint);
228         if (location)
229             locations->pushObject(location);
230     }
231     *outBreakpointId = breakpointId;
232 }
233
234 static bool parseLocation(ErrorString* errorString, RefPtr<InspectorObject> location, String* scriptId, int* lineNumber, int* columnNumber)
235 {
236     if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
237         // FIXME: replace with input validation.
238         *errorString = "scriptId and lineNumber are required.";
239         return false;
240     }
241     *columnNumber = 0;
242     location->getNumber("columnNumber", columnNumber);
243     return true;
244 }
245
246 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, PassRefPtr<InspectorObject> location, const String* const optionalCondition, String* outBreakpointId, RefPtr<InspectorObject>& actualLocation)
247 {
248     String scriptId;
249     int lineNumber;
250     int columnNumber;
251
252     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
253         return;
254
255     String condition = optionalCondition ? *optionalCondition : emptyString();
256
257     String breakpointId = scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
258     if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end())
259         return;
260     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
261     actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint);
262     if (actualLocation)
263         *outBreakpointId = breakpointId;
264     else
265         *errorString = "Could not resolve breakpoint";
266 }
267
268 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId)
269 {
270     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
271     breakpointsCookie->remove(breakpointId);
272     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
273
274     BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
275     if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
276         return;
277     for (size_t i = 0; i < debugServerBreakpointIdsIterator->second.size(); ++i)
278         scriptDebugServer().removeBreakpoint(debugServerBreakpointIdsIterator->second[i]);
279     m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
280 }
281
282 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, PassRefPtr<InspectorObject> location)
283 {
284     if (!m_continueToLocationBreakpointId.isEmpty()) {
285         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
286         m_continueToLocationBreakpointId = "";
287     }
288
289     String scriptId;
290     int lineNumber;
291     int columnNumber;
292
293     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
294         return;
295
296     ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
297     m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber);
298     resume(errorString);
299 }
300
301 PassRefPtr<InspectorObject> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint)
302 {
303     ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
304     if (scriptIterator == m_scripts.end())
305         return 0;
306     Script& script = scriptIterator->second;
307     if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber)
308         return 0;
309
310     int actualLineNumber;
311     int actualColumnNumber;
312     String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber);
313     if (debugServerBreakpointId.isEmpty())
314         return 0;
315
316     BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
317     if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
318         debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).first;
319     debugServerBreakpointIdsIterator->second.append(debugServerBreakpointId);
320
321     RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
322         .setScriptId(scriptId)
323         .setLineNumber(actualLineNumber);
324     location->setColumnNumber(actualColumnNumber);
325     return location;
326 }
327
328 static PassRefPtr<InspectorObject> scriptToInspectorObject(ScriptObject scriptObject)
329 {
330     if (scriptObject.hasNoValue())
331         return 0;
332     RefPtr<InspectorValue> value = scriptObject.toInspectorValue(scriptObject.scriptState());
333     if (!value)
334         return 0;
335     return value->asObject();
336 }
337
338 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<InspectorArray>& results)
339 {
340     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
341     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
342
343     ScriptsMap::iterator it = m_scripts.find(scriptId);
344     if (it != m_scripts.end())
345         results = ContentSearchUtils::searchInTextByLines(it->second.source, query, caseSensitive, isRegex);
346     else
347         *error = "No script for id: " + scriptId;
348 }
349
350 void InspectorDebuggerAgent::setScriptSource(ErrorString* error, const String& scriptId, const String& newContent, const bool* const preview, RefPtr<InspectorArray>& newCallFrames, RefPtr<InspectorObject>& result)
351 {
352     bool previewOnly = preview && *preview;
353     ScriptObject resultObject;
354     if (!scriptDebugServer().setScriptSource(scriptId, newContent, previewOnly, error, &m_currentCallStack, &resultObject))
355         return;
356     newCallFrames = currentCallFrames();
357     RefPtr<InspectorObject> object = scriptToInspectorObject(resultObject);
358     if (object)
359         result = object;
360 }
361
362 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource)
363 {
364     ScriptsMap::iterator it = m_scripts.find(scriptId);
365     if (it != m_scripts.end())
366         *scriptSource = it->second.source;
367     else
368         *error = "No script for id: " + scriptId;
369 }
370
371 void InspectorDebuggerAgent::getFunctionLocation(ErrorString* errorString, const String& functionId, RefPtr<InspectorObject>& location)
372 {
373     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
374     if (injectedScript.hasNoValue()) {
375         *errorString = "Inspected frame has gone";
376         return;
377     }
378     injectedScript.getFunctionLocation(errorString, functionId, &location);
379 }
380
381 void InspectorDebuggerAgent::schedulePauseOnNextStatement(const String& breakReason, PassRefPtr<InspectorObject> data)
382 {
383     if (m_javaScriptPauseScheduled)
384         return;
385     m_breakReason = breakReason;
386     m_breakAuxData = data;
387     scriptDebugServer().setPauseOnNextStatement(true);
388 }
389
390 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
391 {
392     if (m_javaScriptPauseScheduled)
393         return;
394     clearBreakDetails();
395     scriptDebugServer().setPauseOnNextStatement(false);
396 }
397
398 void InspectorDebuggerAgent::pause(ErrorString*)
399 {
400     if (m_javaScriptPauseScheduled)
401         return;
402     clearBreakDetails();
403     scriptDebugServer().setPauseOnNextStatement(true);
404     m_javaScriptPauseScheduled = true;
405 }
406
407 void InspectorDebuggerAgent::resume(ErrorString* errorString)
408 {
409     if (!assertPaused(errorString))
410         return;
411     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
412     scriptDebugServer().continueProgram();
413 }
414
415 void InspectorDebuggerAgent::stepOver(ErrorString* errorString)
416 {
417     if (!assertPaused(errorString))
418         return;
419     scriptDebugServer().stepOverStatement();
420 }
421
422 void InspectorDebuggerAgent::stepInto(ErrorString* errorString)
423 {
424     if (!assertPaused(errorString))
425         return;
426     scriptDebugServer().stepIntoStatement();
427 }
428
429 void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
430 {
431     if (!assertPaused(errorString))
432         return;
433     scriptDebugServer().stepOutOfFunction();
434 }
435
436 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState)
437 {
438     ScriptDebugServer::PauseOnExceptionsState pauseState;
439     if (stringPauseState == "none")
440         pauseState = ScriptDebugServer::DontPauseOnExceptions;
441     else if (stringPauseState == "all")
442         pauseState = ScriptDebugServer::PauseOnAllExceptions;
443     else if (stringPauseState == "uncaught")
444         pauseState = ScriptDebugServer::PauseOnUncaughtExceptions;
445     else {
446         *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
447         return;
448     }
449     scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState));
450     if (scriptDebugServer().pauseOnExceptionsState() != pauseState)
451         *errorString = "Internal error. Could not change pause on exceptions state";
452 }
453
454 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const returnByValue, RefPtr<InspectorObject>& result, bool* wasThrown)
455 {
456     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
457     if (injectedScript.hasNoValue()) {
458         *errorString = "Inspected frame has gone";
459         return;
460     }
461     injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, &result, wasThrown);
462 }
463
464 PassRefPtr<InspectorArray> InspectorDebuggerAgent::currentCallFrames()
465 {
466     if (!m_pausedScriptState)
467         return InspectorArray::create();
468     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState);
469     if (injectedScript.hasNoValue()) {
470         ASSERT_NOT_REACHED();
471         return InspectorArray::create();
472     }
473     return injectedScript.wrapCallFrames(m_currentCallStack);
474 }
475
476 // JavaScriptDebugListener functions
477
478 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script)
479 {
480     // Don't send script content to the front end until it's really needed.
481     m_frontend->scriptParsed(scriptId, script.url, script.startLine, script.startColumn, script.endLine, script.endColumn, script.isContentScript ? &script.isContentScript : 0);
482
483     m_scripts.set(scriptId, script);
484
485     if (script.url.isEmpty())
486         return;
487
488     RefPtr<InspectorObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
489     for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
490         RefPtr<InspectorObject> breakpointObject = it->second->asObject();
491         bool isRegex;
492         breakpointObject->getBoolean("isRegex", &isRegex);
493         String url;
494         breakpointObject->getString("url", &url);
495         if (!matches(script.url, url, isRegex))
496             continue;
497         ScriptBreakpoint breakpoint;
498         breakpointObject->getNumber("lineNumber", &breakpoint.lineNumber);
499         breakpointObject->getNumber("columnNumber", &breakpoint.columnNumber);
500         breakpointObject->getString("condition", &breakpoint.condition);
501         RefPtr<InspectorObject> location = resolveBreakpoint(it->first, scriptId, breakpoint);
502         if (location)
503             m_frontend->breakpointResolved(it->first, location);
504     }
505 }
506
507 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
508 {
509     m_frontend->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage);
510 }
511
512 void InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception)
513 {
514     ASSERT(scriptState && !m_pausedScriptState);
515     m_pausedScriptState = scriptState;
516     m_currentCallStack = callFrames;
517
518     if (!exception.hasNoValue()) {
519         InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
520         if (!injectedScript.hasNoValue()) {
521             m_breakReason = "exception";
522             m_breakAuxData = injectedScript.wrapObject(exception, "backtrace");
523         }
524     }
525
526     m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData);
527     m_javaScriptPauseScheduled = false;
528
529     if (!m_continueToLocationBreakpointId.isEmpty()) {
530         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
531         m_continueToLocationBreakpointId = "";
532     }
533 }
534
535 void InspectorDebuggerAgent::didContinue()
536 {
537     m_pausedScriptState = 0;
538     m_currentCallStack = ScriptValue();
539     clearBreakDetails();
540     m_frontend->resumed();
541 }
542
543 void InspectorDebuggerAgent::breakProgram(const String& breakReason, PassRefPtr<InspectorObject> data)
544 {
545     m_breakReason = breakReason;
546     m_breakAuxData = data;
547     scriptDebugServer().breakProgram();
548 }
549
550 void InspectorDebuggerAgent::clear()
551 {
552     m_pausedScriptState = 0;
553     m_currentCallStack = ScriptValue();
554     m_scripts.clear();
555     m_breakpointIdToDebugServerBreakpointIds.clear();
556     m_continueToLocationBreakpointId = String();
557     clearBreakDetails();
558     m_javaScriptPauseScheduled = false;
559 }
560
561 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString)
562 {
563     if (!m_pausedScriptState) {
564         *errorString = "Can only perform operation while paused.";
565         return false;
566     }
567     return true;
568 }
569
570 void InspectorDebuggerAgent::clearBreakDetails()
571 {
572     m_breakReason = "other";
573     m_breakAuxData = 0;
574 }
575
576 } // namespace WebCore
577
578 #endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)