DebuggerModel.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. /*
  2. * Copyright (C) 2010 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @extends {WebInspector.Object}
  33. */
  34. WebInspector.DebuggerModel = function()
  35. {
  36. InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerDispatcher(this));
  37. this._debuggerPausedDetails = null;
  38. /**
  39. * @type {Object.<string, WebInspector.Script>}
  40. */
  41. this._scripts = {};
  42. /** @type {!Object.<!string, !Array.<!WebInspector.Script>>} */
  43. this._scriptsBySourceURL = {};
  44. this._canSetScriptSource = false;
  45. this._breakpointsActive = true;
  46. WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.DebuggerModel.PauseOnExceptionsState.DontPauseOnExceptions);
  47. WebInspector.settings.pauseOnExceptionStateString.addChangeListener(this._pauseOnExceptionStateChanged, this);
  48. this.enableDebugger();
  49. WebInspector.DebuggerModel.applySkipStackFrameSettings();
  50. }
  51. // Keep these in sync with WebCore::ScriptDebugServer
  52. WebInspector.DebuggerModel.PauseOnExceptionsState = {
  53. DontPauseOnExceptions : "none",
  54. PauseOnAllExceptions : "all",
  55. PauseOnUncaughtExceptions: "uncaught"
  56. };
  57. /**
  58. * @constructor
  59. * @implements {WebInspector.RawLocation}
  60. * @param {string} scriptId
  61. * @param {number} lineNumber
  62. * @param {number} columnNumber
  63. */
  64. WebInspector.DebuggerModel.Location = function(scriptId, lineNumber, columnNumber)
  65. {
  66. this.scriptId = scriptId;
  67. this.lineNumber = lineNumber;
  68. this.columnNumber = columnNumber;
  69. }
  70. WebInspector.DebuggerModel.Events = {
  71. DebuggerWasEnabled: "DebuggerWasEnabled",
  72. DebuggerWasDisabled: "DebuggerWasDisabled",
  73. DebuggerPaused: "DebuggerPaused",
  74. DebuggerResumed: "DebuggerResumed",
  75. ParsedScriptSource: "ParsedScriptSource",
  76. FailedToParseScriptSource: "FailedToParseScriptSource",
  77. BreakpointResolved: "BreakpointResolved",
  78. GlobalObjectCleared: "GlobalObjectCleared",
  79. CallFrameSelected: "CallFrameSelected",
  80. ConsoleCommandEvaluatedInSelectedCallFrame: "ConsoleCommandEvaluatedInSelectedCallFrame",
  81. BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged"
  82. }
  83. WebInspector.DebuggerModel.BreakReason = {
  84. DOM: "DOM",
  85. EventListener: "EventListener",
  86. XHR: "XHR",
  87. Exception: "exception",
  88. Assert: "assert",
  89. CSPViolation: "CSPViolation",
  90. DebugCommand: "debugCommand"
  91. }
  92. WebInspector.DebuggerModel.prototype = {
  93. /**
  94. * @return {boolean}
  95. */
  96. debuggerEnabled: function()
  97. {
  98. return !!this._debuggerEnabled;
  99. },
  100. enableDebugger: function()
  101. {
  102. if (this._debuggerEnabled)
  103. return;
  104. function callback(error, result)
  105. {
  106. this._canSetScriptSource = result;
  107. }
  108. DebuggerAgent.canSetScriptSource(callback.bind(this));
  109. DebuggerAgent.enable(this._debuggerWasEnabled.bind(this));
  110. },
  111. disableDebugger: function()
  112. {
  113. if (!this._debuggerEnabled)
  114. return;
  115. DebuggerAgent.disable(this._debuggerWasDisabled.bind(this));
  116. },
  117. /**
  118. * @return {boolean}
  119. */
  120. canSetScriptSource: function()
  121. {
  122. return this._canSetScriptSource;
  123. },
  124. _debuggerWasEnabled: function()
  125. {
  126. this._debuggerEnabled = true;
  127. this._pauseOnExceptionStateChanged();
  128. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasEnabled);
  129. },
  130. _pauseOnExceptionStateChanged: function()
  131. {
  132. DebuggerAgent.setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
  133. },
  134. _debuggerWasDisabled: function()
  135. {
  136. this._debuggerEnabled = false;
  137. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasDisabled);
  138. },
  139. /**
  140. * @param {WebInspector.DebuggerModel.Location} rawLocation
  141. */
  142. continueToLocation: function(rawLocation)
  143. {
  144. DebuggerAgent.continueToLocation(rawLocation);
  145. },
  146. /**
  147. * @param {WebInspector.DebuggerModel.Location} rawLocation
  148. */
  149. stepIntoSelection: function(rawLocation)
  150. {
  151. /**
  152. * @param {WebInspector.DebuggerModel.Location} requestedLocation
  153. * @param {?string} error
  154. */
  155. function callback(requestedLocation, error)
  156. {
  157. if (error)
  158. return;
  159. this._pendingStepIntoLocation = requestedLocation;
  160. };
  161. DebuggerAgent.continueToLocation(rawLocation, true, callback.bind(this, rawLocation));
  162. },
  163. /**
  164. * @param {WebInspector.DebuggerModel.Location} rawLocation
  165. * @param {string} condition
  166. * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>):void=} callback
  167. */
  168. setBreakpointByScriptLocation: function(rawLocation, condition, callback)
  169. {
  170. var script = this.scriptForId(rawLocation.scriptId);
  171. if (script.sourceURL)
  172. this.setBreakpointByURL(script.sourceURL, rawLocation.lineNumber, rawLocation.columnNumber, condition, callback);
  173. else
  174. this.setBreakpointBySourceId(rawLocation, condition, callback);
  175. },
  176. /**
  177. * @param {string} url
  178. * @param {number} lineNumber
  179. * @param {number=} columnNumber
  180. * @param {string=} condition
  181. * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>)=} callback
  182. */
  183. setBreakpointByURL: function(url, lineNumber, columnNumber, condition, callback)
  184. {
  185. // Adjust column if needed.
  186. var minColumnNumber = 0;
  187. var scripts = this._scriptsBySourceURL[url] || [];
  188. for (var i = 0, l = scripts.length; i < l; ++i) {
  189. var script = scripts[i];
  190. if (lineNumber === script.lineOffset)
  191. minColumnNumber = minColumnNumber ? Math.min(minColumnNumber, script.columnOffset) : script.columnOffset;
  192. }
  193. columnNumber = Math.max(columnNumber, minColumnNumber);
  194. /**
  195. * @this {WebInspector.DebuggerModel}
  196. * @param {?Protocol.Error} error
  197. * @param {DebuggerAgent.BreakpointId} breakpointId
  198. * @param {Array.<DebuggerAgent.Location>} locations
  199. */
  200. function didSetBreakpoint(error, breakpointId, locations)
  201. {
  202. if (callback) {
  203. var rawLocations = /** @type {Array.<WebInspector.DebuggerModel.Location>} */ (locations);
  204. callback(error ? null : breakpointId, rawLocations);
  205. }
  206. }
  207. DebuggerAgent.setBreakpointByUrl(lineNumber, url, undefined, columnNumber, condition, undefined, didSetBreakpoint.bind(this));
  208. WebInspector.userMetrics.ScriptsBreakpointSet.record();
  209. },
  210. /**
  211. * @param {WebInspector.DebuggerModel.Location} rawLocation
  212. * @param {string} condition
  213. * @param {function(?DebuggerAgent.BreakpointId, Array.<WebInspector.DebuggerModel.Location>)=} callback
  214. */
  215. setBreakpointBySourceId: function(rawLocation, condition, callback)
  216. {
  217. /**
  218. * @this {WebInspector.DebuggerModel}
  219. * @param {?Protocol.Error} error
  220. * @param {DebuggerAgent.BreakpointId} breakpointId
  221. * @param {DebuggerAgent.Location} actualLocation
  222. */
  223. function didSetBreakpoint(error, breakpointId, actualLocation)
  224. {
  225. if (callback) {
  226. var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (actualLocation);
  227. callback(error ? null : breakpointId, [rawLocation]);
  228. }
  229. }
  230. DebuggerAgent.setBreakpoint(rawLocation, condition, didSetBreakpoint.bind(this));
  231. WebInspector.userMetrics.ScriptsBreakpointSet.record();
  232. },
  233. /**
  234. * @param {DebuggerAgent.BreakpointId} breakpointId
  235. * @param {function(?Protocol.Error)=} callback
  236. */
  237. removeBreakpoint: function(breakpointId, callback)
  238. {
  239. DebuggerAgent.removeBreakpoint(breakpointId, callback);
  240. },
  241. /**
  242. * @param {DebuggerAgent.BreakpointId} breakpointId
  243. * @param {DebuggerAgent.Location} location
  244. */
  245. _breakpointResolved: function(breakpointId, location)
  246. {
  247. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, {breakpointId: breakpointId, location: location});
  248. },
  249. _globalObjectCleared: function()
  250. {
  251. this._setDebuggerPausedDetails(null);
  252. this._reset();
  253. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.GlobalObjectCleared);
  254. },
  255. _reset: function()
  256. {
  257. this._scripts = {};
  258. this._scriptsBySourceURL = {};
  259. },
  260. /**
  261. * @return {Object.<string, WebInspector.Script>}
  262. */
  263. get scripts()
  264. {
  265. return this._scripts;
  266. },
  267. /**
  268. * @param {DebuggerAgent.ScriptId} scriptId
  269. * @return {WebInspector.Script}
  270. */
  271. scriptForId: function(scriptId)
  272. {
  273. return this._scripts[scriptId] || null;
  274. },
  275. /**
  276. * @return {!Array.<!WebInspector.Script>}
  277. */
  278. scriptsForSourceURL: function(sourceURL)
  279. {
  280. if (!sourceURL)
  281. return [];
  282. return this._scriptsBySourceURL[sourceURL] || [];
  283. },
  284. /**
  285. * @param {DebuggerAgent.ScriptId} scriptId
  286. * @param {string} newSource
  287. * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
  288. */
  289. setScriptSource: function(scriptId, newSource, callback)
  290. {
  291. this._scripts[scriptId].editSource(newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
  292. },
  293. /**
  294. * @param {DebuggerAgent.ScriptId} scriptId
  295. * @param {string} newSource
  296. * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
  297. * @param {?Protocol.Error} error
  298. * @param {DebuggerAgent.SetScriptSourceError=} errorData
  299. * @param {Array.<DebuggerAgent.CallFrame>=} callFrames
  300. * @param {boolean=} needsStepIn
  301. */
  302. _didEditScriptSource: function(scriptId, newSource, callback, error, errorData, callFrames, needsStepIn)
  303. {
  304. callback(error, errorData);
  305. if (needsStepIn)
  306. DebuggerAgent.stepInto();
  307. else if (!error && callFrames && callFrames.length)
  308. this._pausedScript(callFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
  309. },
  310. /**
  311. * @return {Array.<DebuggerAgent.CallFrame>}
  312. */
  313. get callFrames()
  314. {
  315. return this._debuggerPausedDetails ? this._debuggerPausedDetails.callFrames : null;
  316. },
  317. /**
  318. * @return {?WebInspector.DebuggerPausedDetails}
  319. */
  320. debuggerPausedDetails: function()
  321. {
  322. return this._debuggerPausedDetails;
  323. },
  324. /**
  325. * @param {?WebInspector.DebuggerPausedDetails} debuggerPausedDetails
  326. */
  327. _setDebuggerPausedDetails: function(debuggerPausedDetails)
  328. {
  329. if (this._debuggerPausedDetails)
  330. this._debuggerPausedDetails.dispose();
  331. this._debuggerPausedDetails = debuggerPausedDetails;
  332. if (this._debuggerPausedDetails)
  333. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPausedDetails);
  334. if (debuggerPausedDetails) {
  335. this.setSelectedCallFrame(debuggerPausedDetails.callFrames[0]);
  336. DebuggerAgent.setOverlayMessage(WebInspector.UIString("Paused in debugger"));
  337. } else {
  338. this.setSelectedCallFrame(null);
  339. DebuggerAgent.setOverlayMessage();
  340. }
  341. },
  342. /**
  343. * @param {Array.<DebuggerAgent.CallFrame>} callFrames
  344. * @param {string} reason
  345. * @param {Object|undefined} auxData
  346. * @param {Array.<string>} breakpointIds
  347. */
  348. _pausedScript: function(callFrames, reason, auxData, breakpointIds)
  349. {
  350. if (this._pendingStepIntoLocation) {
  351. var requestedLocation = this._pendingStepIntoLocation;
  352. delete this._pendingStepIntoLocation;
  353. if (callFrames.length > 0) {
  354. var topLocation = callFrames[0].location;
  355. if (topLocation.lineNumber == requestedLocation.lineNumber && topLocation.columnNumber == requestedLocation.columnNumber && topLocation.scriptId == requestedLocation.scriptId) {
  356. DebuggerAgent.stepInto();
  357. return;
  358. }
  359. }
  360. }
  361. this._setDebuggerPausedDetails(new WebInspector.DebuggerPausedDetails(this, callFrames, reason, auxData, breakpointIds));
  362. },
  363. _resumedScript: function()
  364. {
  365. this._setDebuggerPausedDetails(null);
  366. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
  367. },
  368. /**
  369. * @param {DebuggerAgent.ScriptId} scriptId
  370. * @param {string} sourceURL
  371. * @param {number} startLine
  372. * @param {number} startColumn
  373. * @param {number} endLine
  374. * @param {number} endColumn
  375. * @param {boolean} isContentScript
  376. * @param {string=} sourceMapURL
  377. * @param {boolean=} hasSourceURL
  378. */
  379. _parsedScriptSource: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
  380. {
  381. var script = new WebInspector.Script(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL);
  382. this._registerScript(script);
  383. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script);
  384. },
  385. /**
  386. * @param {WebInspector.Script} script
  387. */
  388. _registerScript: function(script)
  389. {
  390. this._scripts[script.scriptId] = script;
  391. if (script.isAnonymousScript())
  392. return;
  393. var scripts = this._scriptsBySourceURL[script.sourceURL];
  394. if (!scripts) {
  395. scripts = [];
  396. this._scriptsBySourceURL[script.sourceURL] = scripts;
  397. }
  398. scripts.push(script);
  399. },
  400. /**
  401. * @param {WebInspector.Script} script
  402. * @param {number} lineNumber
  403. * @param {number} columnNumber
  404. * @return {WebInspector.DebuggerModel.Location}
  405. */
  406. createRawLocation: function(script, lineNumber, columnNumber)
  407. {
  408. if (script.sourceURL)
  409. return this.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber)
  410. return new WebInspector.DebuggerModel.Location(script.scriptId, lineNumber, columnNumber);
  411. },
  412. /**
  413. * @param {string} sourceURL
  414. * @param {number} lineNumber
  415. * @param {number} columnNumber
  416. * @return {WebInspector.DebuggerModel.Location}
  417. */
  418. createRawLocationByURL: function(sourceURL, lineNumber, columnNumber)
  419. {
  420. var closestScript = null;
  421. var scripts = this._scriptsBySourceURL[sourceURL] || [];
  422. for (var i = 0, l = scripts.length; i < l; ++i) {
  423. var script = scripts[i];
  424. if (!closestScript)
  425. closestScript = script;
  426. if (script.lineOffset > lineNumber || (script.lineOffset === lineNumber && script.columnOffset > columnNumber))
  427. continue;
  428. if (script.endLine < lineNumber || (script.endLine === lineNumber && script.endColumn <= columnNumber))
  429. continue;
  430. closestScript = script;
  431. break;
  432. }
  433. return closestScript ? new WebInspector.DebuggerModel.Location(closestScript.scriptId, lineNumber, columnNumber) : null;
  434. },
  435. /**
  436. * @return {boolean}
  437. */
  438. isPaused: function()
  439. {
  440. return !!this.debuggerPausedDetails();
  441. },
  442. /**
  443. * @param {?WebInspector.DebuggerModel.CallFrame} callFrame
  444. */
  445. setSelectedCallFrame: function(callFrame)
  446. {
  447. this._selectedCallFrame = callFrame;
  448. if (!this._selectedCallFrame)
  449. return;
  450. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.CallFrameSelected, callFrame);
  451. },
  452. /**
  453. * @return {?WebInspector.DebuggerModel.CallFrame}
  454. */
  455. selectedCallFrame: function()
  456. {
  457. return this._selectedCallFrame;
  458. },
  459. /**
  460. * @param {string} code
  461. * @param {string} objectGroup
  462. * @param {boolean} includeCommandLineAPI
  463. * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
  464. * @param {boolean} returnByValue
  465. * @param {boolean} generatePreview
  466. * @param {function(?WebInspector.RemoteObject, boolean, RuntimeAgent.RemoteObject=)} callback
  467. */
  468. evaluateOnSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
  469. {
  470. /**
  471. * @param {?RuntimeAgent.RemoteObject} result
  472. * @param {boolean=} wasThrown
  473. */
  474. function didEvaluate(result, wasThrown)
  475. {
  476. if (returnByValue)
  477. callback(null, !!wasThrown, wasThrown ? null : result);
  478. else
  479. callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown);
  480. if (objectGroup === "console")
  481. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame);
  482. }
  483. this.selectedCallFrame().evaluate(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluate.bind(this));
  484. },
  485. /**
  486. * @param {function(Object)} callback
  487. */
  488. getSelectedCallFrameVariables: function(callback)
  489. {
  490. var result = { this: true };
  491. var selectedCallFrame = this._selectedCallFrame;
  492. if (!selectedCallFrame)
  493. callback(result);
  494. var pendingRequests = 0;
  495. function propertiesCollected(properties)
  496. {
  497. for (var i = 0; properties && i < properties.length; ++i)
  498. result[properties[i].name] = true;
  499. if (--pendingRequests == 0)
  500. callback(result);
  501. }
  502. for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
  503. var scope = selectedCallFrame.scopeChain[i];
  504. var object = WebInspector.RemoteObject.fromPayload(scope.object);
  505. pendingRequests++;
  506. object.getAllProperties(false, propertiesCollected);
  507. }
  508. },
  509. /**
  510. * @param {boolean} active
  511. */
  512. setBreakpointsActive: function(active)
  513. {
  514. if (this._breakpointsActive === active)
  515. return;
  516. this._breakpointsActive = active;
  517. DebuggerAgent.setBreakpointsActive(active);
  518. this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, active);
  519. },
  520. /**
  521. * @return {boolean}
  522. */
  523. breakpointsActive: function()
  524. {
  525. return this._breakpointsActive;
  526. },
  527. /**
  528. * @param {WebInspector.DebuggerModel.Location} rawLocation
  529. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  530. * @return {WebInspector.Script.Location}
  531. */
  532. createLiveLocation: function(rawLocation, updateDelegate)
  533. {
  534. var script = this._scripts[rawLocation.scriptId];
  535. return script.createLiveLocation(rawLocation, updateDelegate);
  536. },
  537. /**
  538. * @param {WebInspector.DebuggerModel.Location} rawLocation
  539. * @return {?WebInspector.UILocation}
  540. */
  541. rawLocationToUILocation: function(rawLocation)
  542. {
  543. var script = this._scripts[rawLocation.scriptId];
  544. if (!script)
  545. return null;
  546. return script.rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
  547. },
  548. /**
  549. * Handles notification from JavaScript VM about updated stack (liveedit or frame restart action).
  550. * @this {WebInspector.DebuggerModel}
  551. * @param {Array.<DebuggerAgent.CallFrame>=} newCallFrames
  552. * @param {Object=} details
  553. */
  554. callStackModified: function(newCallFrames, details)
  555. {
  556. // FIXME: declare this property in protocol and in JavaScript.
  557. if (details && details["stack_update_needs_step_in"])
  558. DebuggerAgent.stepInto();
  559. else {
  560. if (newCallFrames && newCallFrames.length)
  561. this._pausedScript(newCallFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
  562. }
  563. },
  564. __proto__: WebInspector.Object.prototype
  565. }
  566. WebInspector.DebuggerModel.applySkipStackFrameSettings = function()
  567. {
  568. if (!WebInspector.experimentsSettings.frameworksDebuggingSupport.isEnabled())
  569. return;
  570. var settings = WebInspector.settings;
  571. var patternParameter = settings.skipStackFramesSwitch.get() ? settings.skipStackFramesPattern.get() : undefined;
  572. DebuggerAgent.skipStackFrames(patternParameter);
  573. }
  574. WebInspector.DebuggerEventTypes = {
  575. JavaScriptPause: 0,
  576. JavaScriptBreakpoint: 1,
  577. NativeBreakpoint: 2
  578. };
  579. /**
  580. * @constructor
  581. * @implements {DebuggerAgent.Dispatcher}
  582. * @param {WebInspector.DebuggerModel} debuggerModel
  583. */
  584. WebInspector.DebuggerDispatcher = function(debuggerModel)
  585. {
  586. this._debuggerModel = debuggerModel;
  587. }
  588. WebInspector.DebuggerDispatcher.prototype = {
  589. /**
  590. * @param {Array.<DebuggerAgent.CallFrame>} callFrames
  591. * @param {string} reason
  592. * @param {Object=} auxData
  593. * @param {Array.<string>=} breakpointIds
  594. */
  595. paused: function(callFrames, reason, auxData, breakpointIds)
  596. {
  597. this._debuggerModel._pausedScript(callFrames, reason, auxData, breakpointIds || []);
  598. },
  599. resumed: function()
  600. {
  601. this._debuggerModel._resumedScript();
  602. },
  603. globalObjectCleared: function()
  604. {
  605. this._debuggerModel._globalObjectCleared();
  606. },
  607. /**
  608. * @param {DebuggerAgent.ScriptId} scriptId
  609. * @param {string} sourceURL
  610. * @param {number} startLine
  611. * @param {number} startColumn
  612. * @param {number} endLine
  613. * @param {number} endColumn
  614. * @param {boolean=} isContentScript
  615. * @param {string=} sourceMapURL
  616. * @param {boolean=} hasSourceURL
  617. */
  618. scriptParsed: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
  619. {
  620. this._debuggerModel._parsedScriptSource(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, !!isContentScript, sourceMapURL, hasSourceURL);
  621. },
  622. /**
  623. * @param {string} sourceURL
  624. * @param {string} source
  625. * @param {number} startingLine
  626. * @param {number} errorLine
  627. * @param {string} errorMessage
  628. */
  629. scriptFailedToParse: function(sourceURL, source, startingLine, errorLine, errorMessage)
  630. {
  631. },
  632. /**
  633. * @param {DebuggerAgent.BreakpointId} breakpointId
  634. * @param {DebuggerAgent.Location} location
  635. */
  636. breakpointResolved: function(breakpointId, location)
  637. {
  638. this._debuggerModel._breakpointResolved(breakpointId, location);
  639. }
  640. }
  641. /**
  642. * @constructor
  643. * @param {WebInspector.Script} script
  644. * @param {DebuggerAgent.CallFrame} payload
  645. */
  646. WebInspector.DebuggerModel.CallFrame = function(script, payload)
  647. {
  648. this._script = script;
  649. this._payload = payload;
  650. this._locations = [];
  651. }
  652. WebInspector.DebuggerModel.CallFrame.prototype = {
  653. /**
  654. * @return {WebInspector.Script}
  655. */
  656. get script()
  657. {
  658. return this._script;
  659. },
  660. /**
  661. * @return {string}
  662. */
  663. get type()
  664. {
  665. return this._payload.type;
  666. },
  667. /**
  668. * @return {string}
  669. */
  670. get id()
  671. {
  672. return this._payload.callFrameId;
  673. },
  674. /**
  675. * @return {Array.<DebuggerAgent.Scope>}
  676. */
  677. get scopeChain()
  678. {
  679. return this._payload.scopeChain;
  680. },
  681. /**
  682. * @return {RuntimeAgent.RemoteObject}
  683. */
  684. get this()
  685. {
  686. return this._payload.this;
  687. },
  688. /**
  689. * @return {string}
  690. */
  691. get functionName()
  692. {
  693. return this._payload.functionName;
  694. },
  695. /**
  696. * @return {WebInspector.DebuggerModel.Location}
  697. */
  698. get location()
  699. {
  700. var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (this._payload.location);
  701. return rawLocation;
  702. },
  703. /**
  704. * @param {string} code
  705. * @param {string} objectGroup
  706. * @param {boolean} includeCommandLineAPI
  707. * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
  708. * @param {boolean} returnByValue
  709. * @param {boolean} generatePreview
  710. * @param {function(?RuntimeAgent.RemoteObject, boolean=)=} callback
  711. */
  712. evaluate: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
  713. {
  714. /**
  715. * @this {WebInspector.DebuggerModel.CallFrame}
  716. * @param {?Protocol.Error} error
  717. * @param {RuntimeAgent.RemoteObject} result
  718. * @param {boolean=} wasThrown
  719. */
  720. function didEvaluateOnCallFrame(error, result, wasThrown)
  721. {
  722. if (error) {
  723. console.error(error);
  724. callback(null, false);
  725. return;
  726. }
  727. callback(result, wasThrown);
  728. }
  729. DebuggerAgent.evaluateOnCallFrame(this._payload.callFrameId, code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluateOnCallFrame.bind(this));
  730. },
  731. /**
  732. * @param {function(?Protocol.Error=)=} callback
  733. */
  734. restart: function(callback)
  735. {
  736. /**
  737. * @this {WebInspector.DebuggerModel.CallFrame}
  738. * @param {?Protocol.Error} error
  739. * @param {Array.<DebuggerAgent.CallFrame>=} callFrames
  740. * @param {Object=} details
  741. */
  742. function protocolCallback(error, callFrames, details)
  743. {
  744. if (!error)
  745. WebInspector.debuggerModel.callStackModified(callFrames, details);
  746. if (callback)
  747. callback(error);
  748. }
  749. DebuggerAgent.restartFrame(this._payload.callFrameId, protocolCallback);
  750. },
  751. /**
  752. * @param {function(Array.<DebuggerAgent.Location>)} callback
  753. */
  754. getStepIntoLocations: function(callback)
  755. {
  756. if (this._stepInLocations) {
  757. callback(this._stepInLocations.slice(0));
  758. return;
  759. }
  760. /**
  761. * @param {?string} error
  762. * @param {Array.<DebuggerAgent.Location>=} stepInPositions
  763. */
  764. function getStepInPositionsCallback(error, stepInPositions) {
  765. if (error) {
  766. return;
  767. }
  768. this._stepInLocations = stepInPositions;
  769. callback(this._stepInLocations.slice(0));
  770. }
  771. DebuggerAgent.getStepInPositions(this.id, getStepInPositionsCallback.bind(this));
  772. },
  773. /**
  774. * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
  775. */
  776. createLiveLocation: function(updateDelegate)
  777. {
  778. var location = this._script.createLiveLocation(this.location, updateDelegate);
  779. this._locations.push(location);
  780. return location;
  781. },
  782. dispose: function(updateDelegate)
  783. {
  784. for (var i = 0; i < this._locations.length; ++i)
  785. this._locations[i].dispose();
  786. this._locations = [];
  787. }
  788. }
  789. /**
  790. * @constructor
  791. * @param {WebInspector.DebuggerModel} model
  792. * @param {Array.<DebuggerAgent.CallFrame>} callFrames
  793. * @param {string} reason
  794. * @param {Object|undefined} auxData
  795. * @param {Array.<string>} breakpointIds
  796. */
  797. WebInspector.DebuggerPausedDetails = function(model, callFrames, reason, auxData, breakpointIds)
  798. {
  799. this.callFrames = [];
  800. for (var i = 0; i < callFrames.length; ++i) {
  801. var callFrame = callFrames[i];
  802. var script = model.scriptForId(callFrame.location.scriptId);
  803. if (script)
  804. this.callFrames.push(new WebInspector.DebuggerModel.CallFrame(script, callFrame));
  805. }
  806. this.reason = reason;
  807. this.auxData = auxData;
  808. this.breakpointIds = breakpointIds;
  809. }
  810. WebInspector.DebuggerPausedDetails.prototype = {
  811. dispose: function()
  812. {
  813. for (var i = 0; i < this.callFrames.length; ++i) {
  814. var callFrame = this.callFrames[i];
  815. callFrame.dispose();
  816. }
  817. }
  818. }
  819. /**
  820. * @type {?WebInspector.DebuggerModel}
  821. */
  822. WebInspector.debuggerModel = null;