Home | History | Annotate | Download | only in js
      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 /**
     32  * @fileoverview Provides communication interface to remote v8 debugger. See
     33  * protocol decription at http://code.google.com/p/v8/wiki/DebuggerProtocol
     34  */
     35 
     36 /**
     37  * FIXME: change field naming style to use trailing underscore.
     38  * @constructor
     39  */
     40 devtools.DebuggerAgent = function()
     41 {
     42     RemoteDebuggerAgent.debuggerOutput = this.handleDebuggerOutput_.bind(this);
     43     RemoteDebuggerAgent.setContextId = this.setContextId_.bind(this);
     44 
     45     /**
     46      * Id of the inspected page global context. It is used for filtering scripts.
     47      * @type {number}
     48      */
     49     this.contextId_ = null;
     50 
     51     /**
     52      * Mapping from script id to script info.
     53      * @type {Object}
     54      */
     55     this.parsedScripts_ = null;
     56 
     57     /**
     58      * Mapping from the request id to the devtools.BreakpointInfo for the
     59      * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for
     60      * "setbreakpoint" responses to learn their ids in the v8 debugger.
     61      * @see #handleSetBreakpointResponse_
     62      * @type {Object}
     63      */
     64     this.requestNumberToBreakpointInfo_ = null;
     65 
     66     /**
     67      * Information on current stack frames.
     68      * @type {Array.<devtools.CallFrame>}
     69      */
     70     this.callFrames_ = [];
     71 
     72     /**
     73      * Whether to stop in the debugger on the exceptions.
     74      * @type {boolean}
     75      */
     76     this.pauseOnExceptions_ = false;
     77 
     78     /**
     79      * Mapping: request sequence number->callback.
     80      * @type {Object}
     81      */
     82     this.requestSeqToCallback_ = null;
     83 
     84     /**
     85      * Whether the scripts panel has been shown and initialilzed.
     86      * @type {boolean}
     87      */
     88     this.scriptsPanelInitialized_ = false;
     89 
     90     /**
     91      * Whether the scripts list should be requested next time when context id is
     92      * set.
     93      * @type {boolean}
     94      */
     95     this.requestScriptsWhenContextIdSet_ = false;
     96 
     97     /**
     98      * Whether the agent is waiting for initial scripts response.
     99      * @type {boolean}
    100      */
    101     this.waitingForInitialScriptsResponse_ = false;
    102 
    103     /**
    104      * If backtrace response is received when initial scripts response
    105      * is not yet processed the backtrace handling will be postponed until
    106      * after the scripts response processing. The handler bound to its arguments
    107      * and this agent will be stored in this field then.
    108      * @type {?function()}
    109      */
    110     this.pendingBacktraceResponseHandler_ = null;
    111 
    112     /**
    113      * Container of all breakpoints set using resource URL. These breakpoints
    114      * survive page reload. Breakpoints set by script id(for scripts that don't
    115      * have URLs) are stored in ScriptInfo objects.
    116      * @type {Object}
    117      */
    118     this.urlToBreakpoints_ = {};
    119 
    120 
    121     /**
    122      * Exception message that is shown to user while on exception break.
    123      * @type {WebInspector.ConsoleMessage}
    124      */
    125     this.currentExceptionMessage_ = null;
    126 };
    127 
    128 
    129 /**
    130  * A copy of the scope types from v8/src/mirror-delay.js
    131  * @enum {number}
    132  */
    133 devtools.DebuggerAgent.ScopeType = {
    134     Global: 0,
    135     Local: 1,
    136     With: 2,
    137     Closure: 3,
    138     Catch: 4
    139 };
    140 
    141 
    142 /**
    143  * Resets debugger agent to its initial state.
    144  */
    145 devtools.DebuggerAgent.prototype.reset = function()
    146 {
    147     this.contextId_ = null;
    148     // No need to request scripts since they all will be pushed in AfterCompile
    149     // events.
    150     this.requestScriptsWhenContextIdSet_ = false;
    151     this.waitingForInitialScriptsResponse_ = false;
    152 
    153     this.parsedScripts_ = {};
    154     this.requestNumberToBreakpointInfo_ = {};
    155     this.callFrames_ = [];
    156     this.requestSeqToCallback_ = {};
    157 };
    158 
    159 
    160 /**
    161  * Initializes scripts UI. This method is called every time Scripts panel
    162  * is shown. It will send request for context id if it's not set yet.
    163  */
    164 devtools.DebuggerAgent.prototype.initUI = function()
    165 {
    166     // Initialize scripts cache when Scripts panel is shown first time.
    167     if (this.scriptsPanelInitialized_)
    168         return;
    169     this.scriptsPanelInitialized_ = true;
    170     if (this.contextId_) {
    171         // We already have context id. This means that we are here from the
    172         // very beginning of the page load cycle and hence will get all scripts
    173         // via after-compile events. No need to request scripts for this session.
    174         //
    175         // There can be a number of scripts from after-compile events that are
    176         // pending addition into the UI.
    177         for (var scriptId in this.parsedScripts_) {
    178           var script = this.parsedScripts_[scriptId];
    179           WebInspector.parsedScriptSource(scriptId, script.getUrl(), undefined /* script source */, script.getLineOffset());
    180         }
    181         return;
    182     }
    183     this.waitingForInitialScriptsResponse_ = true;
    184     // Script list should be requested only when current context id is known.
    185     RemoteDebuggerAgent.getContextId();
    186     this.requestScriptsWhenContextIdSet_ = true;
    187 };
    188 
    189 
    190 /**
    191  * Asynchronously requests the debugger for the script source.
    192  * @param {number} scriptId Id of the script whose source should be resolved.
    193  * @param {function(source:?string):void} callback Function that will be called
    194  *     when the source resolution is completed. "source" parameter will be null
    195  *     if the resolution fails.
    196  */
    197 devtools.DebuggerAgent.prototype.resolveScriptSource = function(scriptId, callback)
    198 {
    199     var script = this.parsedScripts_[scriptId];
    200     if (!script || script.isUnresolved()) {
    201         callback(null);
    202         return;
    203     }
    204 
    205     var cmd = new devtools.DebugCommand("scripts", {
    206         "ids": [scriptId],
    207         "includeSource": true
    208     });
    209     devtools.DebuggerAgent.sendCommand_(cmd);
    210     // Force v8 execution so that it gets to processing the requested command.
    211     RemoteDebuggerAgent.processDebugCommands();
    212 
    213     this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
    214         if (msg.isSuccess()) {
    215             var scriptJson = msg.getBody()[0];
    216             if (scriptJson)
    217                 callback(scriptJson.source);
    218             else
    219                 callback(null);
    220         } else
    221             callback(null);
    222     };
    223 };
    224 
    225 
    226 /**
    227  * Tells the v8 debugger to stop on as soon as possible.
    228  */
    229 devtools.DebuggerAgent.prototype.pauseExecution = function()
    230 {
    231     RemoteDebuggerCommandExecutor.DebuggerPauseScript();
    232 };
    233 
    234 
    235 /**
    236  * @param {number} sourceId Id of the script fot the breakpoint.
    237  * @param {number} line Number of the line for the breakpoint.
    238  * @param {?string} condition The breakpoint condition.
    239  */
    240 devtools.DebuggerAgent.prototype.addBreakpoint = function(sourceId, line, condition)
    241 {
    242     var script = this.parsedScripts_[sourceId];
    243     if (!script)
    244         return;
    245 
    246     line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
    247 
    248     var commandArguments;
    249     if (script.getUrl()) {
    250         var breakpoints = this.urlToBreakpoints_[script.getUrl()];
    251         if (breakpoints && breakpoints[line])
    252             return;
    253         if (!breakpoints) {
    254             breakpoints = {};
    255             this.urlToBreakpoints_[script.getUrl()] = breakpoints;
    256         }
    257 
    258         var breakpointInfo = new devtools.BreakpointInfo(line);
    259         breakpoints[line] = breakpointInfo;
    260 
    261         commandArguments = {
    262             "groupId": this.contextId_,
    263             "type": "script",
    264             "target": script.getUrl(),
    265             "line": line,
    266             "condition": condition
    267         };
    268     } else {
    269         var breakpointInfo = script.getBreakpointInfo(line);
    270         if (breakpointInfo)
    271             return;
    272 
    273         breakpointInfo = new devtools.BreakpointInfo(line);
    274         script.addBreakpointInfo(breakpointInfo);
    275 
    276         commandArguments = {
    277             "groupId": this.contextId_,
    278             "type": "scriptId",
    279             "target": sourceId,
    280             "line": line,
    281             "condition": condition
    282         };
    283     }
    284 
    285     var cmd = new devtools.DebugCommand("setbreakpoint", commandArguments);
    286 
    287     this.requestNumberToBreakpointInfo_[cmd.getSequenceNumber()] = breakpointInfo;
    288 
    289     devtools.DebuggerAgent.sendCommand_(cmd);
    290     // Force v8 execution so that it gets to processing the requested command.
    291     // It is necessary for being able to change a breakpoint just after it
    292     // has been created (since we need an existing breakpoint id for that).
    293     RemoteDebuggerAgent.processDebugCommands();
    294 };
    295 
    296 
    297 /**
    298  * @param {number} sourceId Id of the script for the breakpoint.
    299  * @param {number} line Number of the line for the breakpoint.
    300  */
    301 devtools.DebuggerAgent.prototype.removeBreakpoint = function(sourceId, line)
    302 {
    303     var script = this.parsedScripts_[sourceId];
    304     if (!script)
    305         return;
    306 
    307     line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
    308 
    309     var breakpointInfo;
    310     if (script.getUrl()) {
    311         var breakpoints = this.urlToBreakpoints_[script.getUrl()];
    312         breakpointInfo = breakpoints[line];
    313         delete breakpoints[line];
    314     } else {
    315         breakpointInfo = script.getBreakpointInfo(line);
    316         if (breakpointInfo)
    317             script.removeBreakpointInfo(breakpointInfo);
    318     }
    319 
    320     if (!breakpointInfo)
    321         return;
    322 
    323     breakpointInfo.markAsRemoved();
    324 
    325     var id = breakpointInfo.getV8Id();
    326 
    327     // If we don't know id of this breakpoint in the v8 debugger we cannot send
    328     // "clearbreakpoint" request. In that case it will be removed in
    329     // "setbreakpoint" response handler when we learn the id.
    330     if (id !== -1) {
    331         this.requestClearBreakpoint_(id);
    332     }
    333 };
    334 
    335 
    336 /**
    337  * @param {number} sourceId Id of the script for the breakpoint.
    338  * @param {number} line Number of the line for the breakpoint.
    339  * @param {?string} condition New breakpoint condition.
    340  */
    341 devtools.DebuggerAgent.prototype.updateBreakpoint = function(sourceId, line, condition)
    342 {
    343     var script = this.parsedScripts_[sourceId];
    344     if (!script)
    345         return;
    346 
    347     line = devtools.DebuggerAgent.webkitToV8LineNumber_(line);
    348 
    349     var breakpointInfo;
    350     if (script.getUrl()) {
    351         var breakpoints = this.urlToBreakpoints_[script.getUrl()];
    352         breakpointInfo = breakpoints[line];
    353     } else
    354         breakpointInfo = script.getBreakpointInfo(line);
    355 
    356     var id = breakpointInfo.getV8Id();
    357 
    358     // If we don't know id of this breakpoint in the v8 debugger we cannot send
    359     // the "changebreakpoint" request.
    360     if (id !== -1) {
    361         // TODO(apavlov): make use of the real values for "enabled" and
    362         // "ignoreCount" when appropriate.
    363         this.requestChangeBreakpoint_(id, true, condition, null);
    364     }
    365 };
    366 
    367 
    368 /**
    369  * Tells the v8 debugger to step into the next statement.
    370  */
    371 devtools.DebuggerAgent.prototype.stepIntoStatement = function()
    372 {
    373     this.stepCommand_("in");
    374 };
    375 
    376 
    377 /**
    378  * Tells the v8 debugger to step out of current function.
    379  */
    380 devtools.DebuggerAgent.prototype.stepOutOfFunction = function()
    381 {
    382     this.stepCommand_("out");
    383 };
    384 
    385 
    386 /**
    387  * Tells the v8 debugger to step over the next statement.
    388  */
    389 devtools.DebuggerAgent.prototype.stepOverStatement = function()
    390 {
    391     this.stepCommand_("next");
    392 };
    393 
    394 
    395 /**
    396  * Tells the v8 debugger to continue execution after it has been stopped on a
    397  * breakpoint or an exception.
    398  */
    399 devtools.DebuggerAgent.prototype.resumeExecution = function()
    400 {
    401     this.clearExceptionMessage_();
    402     var cmd = new devtools.DebugCommand("continue");
    403     devtools.DebuggerAgent.sendCommand_(cmd);
    404 };
    405 
    406 
    407 /**
    408  * Creates exception message and schedules it for addition to the resource upon
    409  * backtrace availability.
    410  * @param {string} url Resource url.
    411  * @param {number} line Resource line number.
    412  * @param {string} message Exception text.
    413  */
    414 devtools.DebuggerAgent.prototype.createExceptionMessage_ = function(url, line, message)
    415 {
    416     this.currentExceptionMessage_ = new WebInspector.ConsoleMessage(
    417         WebInspector.ConsoleMessage.MessageSource.JS,
    418         WebInspector.ConsoleMessage.MessageType.Log,
    419         WebInspector.ConsoleMessage.MessageLevel.Error,
    420         line,
    421         url,
    422         0 /* group level */,
    423         1 /* repeat count */,
    424         "[Exception] " + message);
    425 };
    426 
    427 
    428 /**
    429  * Shows pending exception message that is created with createExceptionMessage_
    430  * earlier.
    431  */
    432 devtools.DebuggerAgent.prototype.showPendingExceptionMessage_ = function()
    433 {
    434     if (!this.currentExceptionMessage_)
    435         return;
    436     var msg = this.currentExceptionMessage_;
    437     var resource = WebInspector.resourceURLMap[msg.url];
    438     if (resource) {
    439         msg.resource = resource;
    440         WebInspector.panels.resources.addMessageToResource(resource, msg);
    441     } else
    442         this.currentExceptionMessage_ = null;
    443 };
    444 
    445 
    446 /**
    447  * Clears exception message from the resource.
    448  */
    449 devtools.DebuggerAgent.prototype.clearExceptionMessage_ = function()
    450 {
    451     if (this.currentExceptionMessage_) {
    452         var messageElement = this.currentExceptionMessage_._resourceMessageLineElement;
    453         var bubble = messageElement.parentElement;
    454         bubble.removeChild(messageElement);
    455         if (!bubble.firstChild) {
    456             // Last message in bubble removed.
    457             bubble.parentElement.removeChild(bubble);
    458         }
    459         this.currentExceptionMessage_ = null;
    460     }
    461 };
    462 
    463 
    464 /**
    465  * @return {boolean} True iff the debugger will pause execution on the
    466  * exceptions.
    467  */
    468 devtools.DebuggerAgent.prototype.pauseOnExceptions = function()
    469 {
    470     return this.pauseOnExceptions_;
    471 };
    472 
    473 
    474 /**
    475  * Tells whether to pause in the debugger on the exceptions or not.
    476  * @param {boolean} value True iff execution should be stopped in the debugger
    477  * on the exceptions.
    478  */
    479 devtools.DebuggerAgent.prototype.setPauseOnExceptions = function(value)
    480 {
    481     this.pauseOnExceptions_ = value;
    482 };
    483 
    484 
    485 /**
    486  * Sends "evaluate" request to the debugger.
    487  * @param {Object} arguments Request arguments map.
    488  * @param {function(devtools.DebuggerMessage)} callback Callback to be called
    489  *     when response is received.
    490  */
    491 devtools.DebuggerAgent.prototype.requestEvaluate = function(arguments, callback)
    492 {
    493     var cmd = new devtools.DebugCommand("evaluate", arguments);
    494     devtools.DebuggerAgent.sendCommand_(cmd);
    495     this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback;
    496 };
    497 
    498 
    499 /**
    500  * Sends "lookup" request for each unresolved property of the object. When
    501  * response is received the properties will be changed with their resolved
    502  * values.
    503  * @param {Object} object Object whose properties should be resolved.
    504  * @param {function(devtools.DebuggerMessage)} Callback to be called when all
    505  *     children are resolved.
    506  * @param {boolean} noIntrinsic Whether intrinsic properties should be included.
    507  */
    508 devtools.DebuggerAgent.prototype.resolveChildren = function(object, callback, noIntrinsic)
    509 {
    510     if ("handle" in object) {
    511         var result = [];
    512         devtools.DebuggerAgent.formatObjectProperties_(object, result, noIntrinsic);
    513         callback(result);
    514     } else {
    515         this.requestLookup_([object.ref], function(msg) {
    516             var result = [];
    517             if (msg.isSuccess()) {
    518                 var handleToObject = msg.getBody();
    519                 var resolved = handleToObject[object.ref];
    520                 devtools.DebuggerAgent.formatObjectProperties_(resolved, result, noIntrinsic);
    521                 callback(result);
    522             } else
    523                 callback([]);
    524         });
    525     }
    526 };
    527 
    528 
    529 /**
    530  * Sends "scope" request for the scope object to resolve its variables.
    531  * @param {Object} scope Scope to be resolved.
    532  * @param {function(Array.<WebInspector.ObjectPropertyProxy>)} callback
    533  *     Callback to be called when all scope variables are resolved.
    534  */
    535 devtools.DebuggerAgent.prototype.resolveScope = function(scope, callback)
    536 {
    537     var cmd = new devtools.DebugCommand("scope", {
    538         "frameNumber": scope.frameNumber,
    539         "number": scope.index,
    540         "compactFormat": true
    541     });
    542     devtools.DebuggerAgent.sendCommand_(cmd);
    543     this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
    544         var result = [];
    545         if (msg.isSuccess()) {
    546             var scopeObjectJson = msg.getBody().object;
    547             devtools.DebuggerAgent.formatObjectProperties_(scopeObjectJson, result, true /* no intrinsic */);
    548         }
    549         callback(result);
    550     };
    551 };
    552 
    553 
    554 /**
    555  * Sends "scopes" request for the frame object to resolve all variables
    556  * available in the frame.
    557  * @param {number} callFrameId Id of call frame whose variables need to
    558  *     be resolved.
    559  * @param {function(Object)} callback Callback to be called when all frame
    560  *     variables are resolved.
    561  */
    562 devtools.DebuggerAgent.prototype.resolveFrameVariables_ = function(callFrameId, callback)
    563 {
    564     var result = {};
    565 
    566     var frame = this.callFrames_[callFrameId];
    567     if (!frame) {
    568         callback(result);
    569         return;
    570     }
    571 
    572     var waitingResponses = 0;
    573     function scopeResponseHandler(msg) {
    574         waitingResponses--;
    575 
    576         if (msg.isSuccess()) {
    577             var properties = msg.getBody().object.properties;
    578             for (var j = 0; j < properties.length; j++)
    579                 result[properties[j].name] = true;
    580         }
    581 
    582         // When all scopes are resolved invoke the callback.
    583         if (waitingResponses === 0)
    584             callback(result);
    585     };
    586 
    587     for (var i = 0; i < frame.scopeChain.length; i++) {
    588         var scope = frame.scopeChain[i].objectId;
    589         if (scope.type === devtools.DebuggerAgent.ScopeType.Global) {
    590             // Do not resolve global scope since it takes for too long.
    591             // TODO(yurys): allow to send only property names in the response.
    592             continue;
    593         }
    594         var cmd = new devtools.DebugCommand("scope", {
    595             "frameNumber": scope.frameNumber,
    596             "number": scope.index,
    597             "compactFormat": true
    598         });
    599         devtools.DebuggerAgent.sendCommand_(cmd);
    600         this.requestSeqToCallback_[cmd.getSequenceNumber()] = scopeResponseHandler;
    601         waitingResponses++;
    602     }
    603 };
    604 
    605 /**
    606  * Evaluates the expressionString to an object in the call frame and reports
    607  * all its properties.
    608  * @param{string} expressionString Expression whose properties should be
    609  *     collected.
    610  * @param{number} callFrameId The frame id.
    611  * @param{function(Object result,bool isException)} reportCompletions Callback
    612  *     function.
    613  */
    614 devtools.DebuggerAgent.prototype.resolveCompletionsOnFrame = function(expressionString, callFrameId, reportCompletions)
    615 {
    616       if (expressionString) {
    617           expressionString = "var obj = " + expressionString +
    618               "; var names = {}; for (var n in obj) { names[n] = true; };" +
    619               "names;";
    620           this.evaluateInCallFrame(
    621               callFrameId,
    622               expressionString,
    623               function(result) {
    624                   var names = {};
    625                   if (!result.isException) {
    626                       var props = result.value.objectId.properties;
    627                       // Put all object properties into the map.
    628                       for (var i = 0; i < props.length; i++)
    629                           names[props[i].name] = true;
    630                   }
    631                   reportCompletions(names, result.isException);
    632               });
    633       } else {
    634           this.resolveFrameVariables_(callFrameId,
    635               function(result) {
    636                   reportCompletions(result, false /* isException */);
    637               });
    638       }
    639 };
    640 
    641 
    642 /**
    643  * @param{number} scriptId
    644  * @return {string} Type of the context of the script with specified id.
    645  */
    646 devtools.DebuggerAgent.prototype.getScriptContextType = function(scriptId)
    647 {
    648     return this.parsedScripts_[scriptId].getContextType();
    649 };
    650 
    651 
    652 /**
    653  * Removes specified breakpoint from the v8 debugger.
    654  * @param {number} breakpointId Id of the breakpoint in the v8 debugger.
    655  */
    656 devtools.DebuggerAgent.prototype.requestClearBreakpoint_ = function(breakpointId)
    657 {
    658     var cmd = new devtools.DebugCommand("clearbreakpoint", {
    659         "breakpoint": breakpointId
    660     });
    661     devtools.DebuggerAgent.sendCommand_(cmd);
    662 };
    663 
    664 
    665 /**
    666  * Changes breakpoint parameters in the v8 debugger.
    667  * @param {number} breakpointId Id of the breakpoint in the v8 debugger.
    668  * @param {boolean} enabled Whether to enable the breakpoint.
    669  * @param {?string} condition New breakpoint condition.
    670  * @param {number} ignoreCount New ignore count for the breakpoint.
    671  */
    672 devtools.DebuggerAgent.prototype.requestChangeBreakpoint_ = function(breakpointId, enabled, condition, ignoreCount)
    673 {
    674     var cmd = new devtools.DebugCommand("changebreakpoint", {
    675         "breakpoint": breakpointId,
    676         "enabled": enabled,
    677         "condition": condition,
    678         "ignoreCount": ignoreCount
    679     });
    680     devtools.DebuggerAgent.sendCommand_(cmd);
    681 };
    682 
    683 
    684 /**
    685  * Sends "backtrace" request to v8.
    686  */
    687 devtools.DebuggerAgent.prototype.requestBacktrace_ = function()
    688 {
    689     var cmd = new devtools.DebugCommand("backtrace", {
    690         "compactFormat":true
    691     });
    692     devtools.DebuggerAgent.sendCommand_(cmd);
    693 };
    694 
    695 
    696 /**
    697  * Sends command to v8 debugger.
    698  * @param {devtools.DebugCommand} cmd Command to execute.
    699  */
    700 devtools.DebuggerAgent.sendCommand_ = function(cmd)
    701 {
    702     RemoteDebuggerCommandExecutor.DebuggerCommand(cmd.toJSONProtocol());
    703 };
    704 
    705 
    706 /**
    707  * Tells the v8 debugger to make the next execution step.
    708  * @param {string} action "in", "out" or "next" action.
    709  */
    710 devtools.DebuggerAgent.prototype.stepCommand_ = function(action)
    711 {
    712     this.clearExceptionMessage_();
    713     var cmd = new devtools.DebugCommand("continue", {
    714         "stepaction": action,
    715         "stepcount": 1
    716     });
    717     devtools.DebuggerAgent.sendCommand_(cmd);
    718 };
    719 
    720 
    721 /**
    722  * Sends "lookup" request to v8.
    723  * @param {number} handle Handle to the object to lookup.
    724  */
    725 devtools.DebuggerAgent.prototype.requestLookup_ = function(handles, callback)
    726 {
    727     var cmd = new devtools.DebugCommand("lookup", {
    728         "compactFormat":true,
    729         "handles": handles
    730     });
    731     devtools.DebuggerAgent.sendCommand_(cmd);
    732     this.requestSeqToCallback_[cmd.getSequenceNumber()] = callback;
    733 };
    734 
    735 
    736 /**
    737  * Sets debugger context id for scripts filtering.
    738  * @param {number} contextId Id of the inspected page global context.
    739  */
    740 devtools.DebuggerAgent.prototype.setContextId_ = function(contextId)
    741 {
    742     this.contextId_ = contextId;
    743 
    744     // If it's the first time context id is set request scripts list.
    745     if (this.requestScriptsWhenContextIdSet_) {
    746         this.requestScriptsWhenContextIdSet_ = false;
    747         var cmd = new devtools.DebugCommand("scripts", {
    748             "includeSource": false
    749         });
    750         devtools.DebuggerAgent.sendCommand_(cmd);
    751         // Force v8 execution so that it gets to processing the requested command.
    752         RemoteDebuggerAgent.processDebugCommands();
    753 
    754         var debuggerAgent = this;
    755         this.requestSeqToCallback_[cmd.getSequenceNumber()] = function(msg) {
    756             // Handle the response iff the context id hasn't changed since the request
    757             // was issued. Otherwise if the context id did change all up-to-date
    758             // scripts will be pushed in after compile events and there is no need to
    759             // handle the response.
    760             if (contextId === debuggerAgent.contextId_)
    761                 debuggerAgent.handleScriptsResponse_(msg);
    762 
    763             // We received initial scripts response so flush the flag and
    764             // see if there is an unhandled backtrace response.
    765             debuggerAgent.waitingForInitialScriptsResponse_ = false;
    766             if (debuggerAgent.pendingBacktraceResponseHandler_) {
    767                 debuggerAgent.pendingBacktraceResponseHandler_();
    768                 debuggerAgent.pendingBacktraceResponseHandler_ = null;
    769             }
    770         };
    771     }
    772 };
    773 
    774 
    775 /**
    776  * Handles output sent by v8 debugger. The output is either asynchronous event
    777  * or response to a previously sent request.  See protocol definitioun for more
    778  * details on the output format.
    779  * @param {string} output
    780  */
    781 devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output)
    782 {
    783     var msg;
    784     try {
    785         msg = new devtools.DebuggerMessage(output);
    786     } catch(e) {
    787         debugPrint("Failed to handle debugger response:\n" + e);
    788         throw e;
    789     }
    790 
    791     if (msg.getType() === "event") {
    792         if (msg.getEvent() === "break")
    793             this.handleBreakEvent_(msg);
    794         else if (msg.getEvent() === "exception")
    795             this.handleExceptionEvent_(msg);
    796         else if (msg.getEvent() === "afterCompile")
    797             this.handleAfterCompileEvent_(msg);
    798     } else if (msg.getType() === "response") {
    799         if (msg.getCommand() === "scripts")
    800             this.invokeCallbackForResponse_(msg);
    801         else if (msg.getCommand() === "setbreakpoint")
    802             this.handleSetBreakpointResponse_(msg);
    803         else if (msg.getCommand() === "clearbreakpoint")
    804             this.handleClearBreakpointResponse_(msg);
    805         else if (msg.getCommand() === "backtrace")
    806             this.handleBacktraceResponse_(msg);
    807         else if (msg.getCommand() === "lookup")
    808             this.invokeCallbackForResponse_(msg);
    809         else if (msg.getCommand() === "evaluate")
    810             this.invokeCallbackForResponse_(msg);
    811         else if (msg.getCommand() === "scope")
    812             this.invokeCallbackForResponse_(msg);
    813     }
    814 };
    815 
    816 
    817 /**
    818  * @param {devtools.DebuggerMessage} msg
    819  */
    820 devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg)
    821 {
    822     // Force scrips panel to be shown first.
    823     WebInspector.currentPanel = WebInspector.panels.scripts;
    824 
    825     var body = msg.getBody();
    826 
    827     var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine);
    828     this.requestBacktrace_();
    829 };
    830 
    831 
    832 /**
    833  * @param {devtools.DebuggerMessage} msg
    834  */
    835 devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg)
    836 {
    837     // Force scrips panel to be shown first.
    838     WebInspector.currentPanel = WebInspector.panels.scripts;
    839 
    840     var body = msg.getBody();
    841     // No script field in the body means that v8 failed to parse the script. We
    842     // resume execution on parser errors automatically.
    843     if (this.pauseOnExceptions_ && body.script) {
    844         var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(body.sourceLine);
    845         this.createExceptionMessage_(body.script.name, line, body.exception.text);
    846         this.requestBacktrace_();
    847     } else
    848         this.resumeExecution();
    849 };
    850 
    851 
    852 /**
    853  * @param {devtools.DebuggerMessage} msg
    854  */
    855 devtools.DebuggerAgent.prototype.handleScriptsResponse_ = function(msg)
    856 {
    857     var scripts = msg.getBody();
    858     for (var i = 0; i < scripts.length; i++) {
    859         var script = scripts[i];
    860 
    861         // Skip scripts from other tabs.
    862         if (!this.isScriptFromInspectedContext_(script, msg))
    863             continue;
    864 
    865         // We may already have received the info in an afterCompile event.
    866         if (script.id in this.parsedScripts_)
    867             continue;
    868         this.addScriptInfo_(script, msg);
    869     }
    870 };
    871 
    872 
    873 /**
    874  * @param {Object} script Json object representing script.
    875  * @param {devtools.DebuggerMessage} msg Debugger response.
    876  */
    877 devtools.DebuggerAgent.prototype.isScriptFromInspectedContext_ = function(script, msg)
    878 {
    879     if (!script.context) {
    880         // Always ignore scripts from the utility context.
    881         return false;
    882     }
    883     var context = msg.lookup(script.context.ref);
    884     var scriptContextId = context.data;
    885     if (typeof scriptContextId === "undefined")
    886         return false; // Always ignore scripts from the utility context.
    887     if (this.contextId_ === null)
    888         return true;
    889     // Find the id from context data. The context data has the format "type,id".
    890     var comma = context.data.indexOf(",");
    891     if (comma < 0)
    892         return false;
    893     return (context.data.substring(comma + 1) == this.contextId_);
    894 };
    895 
    896 
    897 /**
    898  * @param {devtools.DebuggerMessage} msg
    899  */
    900 devtools.DebuggerAgent.prototype.handleSetBreakpointResponse_ = function(msg)
    901 {
    902     var requestSeq = msg.getRequestSeq();
    903     var breakpointInfo = this.requestNumberToBreakpointInfo_[requestSeq];
    904     if (!breakpointInfo) {
    905         // TODO(yurys): handle this case
    906         return;
    907     }
    908     delete this.requestNumberToBreakpointInfo_[requestSeq];
    909     if (!msg.isSuccess()) {
    910         // TODO(yurys): handle this case
    911         return;
    912     }
    913     var idInV8 = msg.getBody().breakpoint;
    914     breakpointInfo.setV8Id(idInV8);
    915 
    916     if (breakpointInfo.isRemoved())
    917         this.requestClearBreakpoint_(idInV8);
    918 };
    919 
    920 
    921 /**
    922  * @param {devtools.DebuggerMessage} msg
    923  */
    924 devtools.DebuggerAgent.prototype.handleAfterCompileEvent_ = function(msg)
    925 {
    926     if (!this.contextId_) {
    927         // Ignore scripts delta if main request has not been issued yet.
    928         return;
    929     }
    930     var script = msg.getBody().script;
    931 
    932     // Ignore scripts from other tabs.
    933     if (!this.isScriptFromInspectedContext_(script, msg))
    934         return;
    935     this.addScriptInfo_(script, msg);
    936 };
    937 
    938 
    939 /**
    940  * Adds the script info to the local cache. This method assumes that the script
    941  * is not in the cache yet.
    942  * @param {Object} script Script json object from the debugger message.
    943  * @param {devtools.DebuggerMessage} msg Debugger message containing the script
    944  *     data.
    945  */
    946 devtools.DebuggerAgent.prototype.addScriptInfo_ = function(script, msg)
    947 {
    948     var context = msg.lookup(script.context.ref);
    949     var contextType;
    950     // Find the type from context data. The context data has the format
    951     // "type,id".
    952     var comma = context.data.indexOf(",");
    953     if (comma < 0)
    954         return
    955     contextType = context.data.substring(0, comma);
    956     this.parsedScripts_[script.id] = new devtools.ScriptInfo(script.id, script.name, script.lineOffset, contextType);
    957     if (this.scriptsPanelInitialized_) {
    958         // Only report script as parsed after scripts panel has been shown.
    959         WebInspector.parsedScriptSource(script.id, script.name, script.source, script.lineOffset);
    960     }
    961 };
    962 
    963 
    964 /**
    965  * @param {devtools.DebuggerMessage} msg
    966  */
    967 devtools.DebuggerAgent.prototype.handleClearBreakpointResponse_ = function(msg)
    968 {
    969     // Do nothing.
    970 };
    971 
    972 
    973 /**
    974  * Handles response to "backtrace" command.
    975  * @param {devtools.DebuggerMessage} msg
    976  */
    977 devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg)
    978 {
    979     if (this.waitingForInitialScriptsResponse_)
    980         this.pendingBacktraceResponseHandler_ = this.doHandleBacktraceResponse_.bind(this, msg);
    981     else
    982         this.doHandleBacktraceResponse_(msg);
    983 };
    984 
    985 
    986 /**
    987  * @param {devtools.DebuggerMessage} msg
    988  */
    989 devtools.DebuggerAgent.prototype.doHandleBacktraceResponse_ = function(msg)
    990 {
    991     var frames = msg.getBody().frames;
    992     this.callFrames_ = [];
    993     for (var i = 0; i <  frames.length; ++i)
    994         this.callFrames_.push(this.formatCallFrame_(frames[i]));
    995     WebInspector.pausedScript(this.callFrames_);
    996     this.showPendingExceptionMessage_();
    997     InspectorFrontendHost.activateWindow();
    998 };
    999 
   1000 
   1001 /**
   1002  * Evaluates code on given callframe.
   1003  */
   1004 devtools.DebuggerAgent.prototype.evaluateInCallFrame = function(callFrameId, code, callback)
   1005 {
   1006     var callFrame = this.callFrames_[callFrameId];
   1007     callFrame.evaluate_(code, callback);
   1008 };
   1009 
   1010 
   1011 /**
   1012  * Handles response to a command by invoking its callback (if any).
   1013  * @param {devtools.DebuggerMessage} msg
   1014  * @return {boolean} Whether a callback for the given message was found and
   1015  *     excuted.
   1016  */
   1017 devtools.DebuggerAgent.prototype.invokeCallbackForResponse_ = function(msg)
   1018 {
   1019     var callback = this.requestSeqToCallback_[msg.getRequestSeq()];
   1020     if (!callback) {
   1021         // It may happend if reset was called.
   1022         return false;
   1023     }
   1024     delete this.requestSeqToCallback_[msg.getRequestSeq()];
   1025     callback(msg);
   1026     return true;
   1027 };
   1028 
   1029 
   1030 /**
   1031  * @param {Object} stackFrame Frame json object from "backtrace" response.
   1032  * @return {!devtools.CallFrame} Object containing information related to the
   1033  *     call frame in the format expected by ScriptsPanel and its panes.
   1034  */
   1035 devtools.DebuggerAgent.prototype.formatCallFrame_ = function(stackFrame)
   1036 {
   1037     var func = stackFrame.func;
   1038     var sourceId = func.scriptId;
   1039 
   1040     // Add service script if it does not exist.
   1041     var existingScript = this.parsedScripts_[sourceId];
   1042     if (!existingScript) {
   1043         this.parsedScripts_[sourceId] = new devtools.ScriptInfo(sourceId, null /* name */, 0 /* line */, "unknown" /* type */, true /* unresolved */);
   1044         WebInspector.parsedScriptSource(sourceId, null, null, 0);
   1045     }
   1046 
   1047     var funcName = func.name || func.inferredName || "(anonymous function)";
   1048     var line = devtools.DebuggerAgent.v8ToWwebkitLineNumber_(stackFrame.line);
   1049 
   1050     // Add basic scope chain info with scope variables.
   1051     var scopeChain = [];
   1052     var ScopeType = devtools.DebuggerAgent.ScopeType;
   1053     for (var i = 0; i < stackFrame.scopes.length; i++) {
   1054         var scope = stackFrame.scopes[i];
   1055         scope.frameNumber = stackFrame.index;
   1056         var scopeObjectProxy = new WebInspector.ObjectProxy(0, scope, [], 0, "", true);
   1057         scopeObjectProxy.isScope = true;
   1058         switch(scope.type) {
   1059             case ScopeType.Global:
   1060                 scopeObjectProxy.isDocument = true;
   1061                 break;
   1062             case ScopeType.Local:
   1063                 scopeObjectProxy.isLocal = true;
   1064                 scopeObjectProxy.thisObject = devtools.DebuggerAgent.formatObjectProxy_(stackFrame.receiver);
   1065                 break;
   1066             case ScopeType.With:
   1067             // Catch scope is treated as a regular with scope by WebKit so we
   1068             // also treat it this way.
   1069             case ScopeType.Catch:
   1070                 scopeObjectProxy.isWithBlock = true;
   1071                 break;
   1072             case ScopeType.Closure:
   1073                 scopeObjectProxy.isClosure = true;
   1074                 break;
   1075         }
   1076         scopeChain.push(scopeObjectProxy);
   1077     }
   1078     return new devtools.CallFrame(stackFrame.index, "function", funcName, sourceId, line, scopeChain);
   1079 };
   1080 
   1081 
   1082 /**
   1083  * Collects properties for an object from the debugger response.
   1084  * @param {Object} object An object from the debugger protocol response.
   1085  * @param {Array.<WebInspector.ObjectPropertyProxy>} result An array to put the
   1086  *     properties into.
   1087  * @param {boolean} noIntrinsic Whether intrinsic properties should be
   1088  *     included.
   1089  */
   1090 devtools.DebuggerAgent.formatObjectProperties_ = function(object, result, noIntrinsic)
   1091 {
   1092     devtools.DebuggerAgent.propertiesToProxies_(object.properties, result);
   1093     if (noIntrinsic)
   1094         return;
   1095 
   1096     result.push(new WebInspector.ObjectPropertyProxy("__proto__", devtools.DebuggerAgent.formatObjectProxy_(object.protoObject)));
   1097     result.push(new WebInspector.ObjectPropertyProxy("constructor", devtools.DebuggerAgent.formatObjectProxy_(object.constructorFunction)));
   1098     // Don't add 'prototype' property since it is one of the regualar properties.
   1099 };
   1100 
   1101 
   1102 /**
   1103  * For each property in "properties" creates its proxy representative.
   1104  * @param {Array.<Object>} properties Receiver properties or locals array from
   1105  *     "backtrace" response.
   1106  * @param {Array.<WebInspector.ObjectPropertyProxy>} Results holder.
   1107  */
   1108 devtools.DebuggerAgent.propertiesToProxies_ = function(properties, result)
   1109 {
   1110     var map = {};
   1111     for (var i = 0; i < properties.length; ++i) {
   1112         var property = properties[i];
   1113         var name = String(property.name);
   1114         if (name in map)
   1115             continue;
   1116         map[name] = true;
   1117         var value = devtools.DebuggerAgent.formatObjectProxy_(property.value);
   1118         var propertyProxy = new WebInspector.ObjectPropertyProxy(name, value);
   1119         result.push(propertyProxy);
   1120     }
   1121 };
   1122 
   1123 
   1124 /**
   1125  * @param {Object} v An object reference from the debugger response.
   1126  * @return {*} The value representation expected by ScriptsPanel.
   1127  */
   1128 devtools.DebuggerAgent.formatObjectProxy_ = function(v)
   1129 {
   1130     var description;
   1131     var hasChildren = false;
   1132     if (v.type === "object") {
   1133         description = v.className;
   1134         hasChildren = true;
   1135     } else if (v.type === "function") {
   1136         if (v.source)
   1137             description = v.source;
   1138         else
   1139             description = "function " + v.name + "()";
   1140         hasChildren = true;
   1141     } else if (v.type === "undefined")
   1142         description = "undefined";
   1143     else if (v.type === "null")
   1144         description = "null";
   1145     else if (typeof v.value !== "undefined") {
   1146         // Check for undefined and null types before checking the value, otherwise
   1147         // null/undefined may have blank value.
   1148         description = v.value;
   1149     } else
   1150         description = "<unresolved ref: " + v.ref + ", type: " + v.type + ">";
   1151 
   1152     var proxy = new WebInspector.ObjectProxy(0, v, [], 0, description, hasChildren);
   1153     proxy.type = v.type;
   1154     proxy.isV8Ref = true;
   1155     return proxy;
   1156 };
   1157 
   1158 
   1159 /**
   1160  * Converts line number from Web Inspector UI(1-based) to v8(0-based).
   1161  * @param {number} line Resource line number in Web Inspector UI.
   1162  * @return {number} The line number in v8.
   1163  */
   1164 devtools.DebuggerAgent.webkitToV8LineNumber_ = function(line)
   1165 {
   1166     return line - 1;
   1167 };
   1168 
   1169 
   1170 /**
   1171  * Converts line number from v8(0-based) to Web Inspector UI(1-based).
   1172  * @param {number} line Resource line number in v8.
   1173  * @return {number} The line number in Web Inspector.
   1174  */
   1175 devtools.DebuggerAgent.v8ToWwebkitLineNumber_ = function(line)
   1176 {
   1177     return line + 1;
   1178 };
   1179 
   1180 
   1181 /**
   1182  * @param {number} scriptId Id of the script.
   1183  * @param {?string} url Script resource URL if any.
   1184  * @param {number} lineOffset First line 0-based offset in the containing
   1185  *     document.
   1186  * @param {string} contextType Type of the script's context:
   1187  *     "page" - regular script from html page
   1188  *     "injected" - extension content script
   1189  * @param {bool} opt_isUnresolved If true, script will not be resolved.
   1190  * @constructor
   1191  */
   1192 devtools.ScriptInfo = function(scriptId, url, lineOffset, contextType, opt_isUnresolved)
   1193 {
   1194     this.scriptId_ = scriptId;
   1195     this.lineOffset_ = lineOffset;
   1196     this.contextType_ = contextType;
   1197     this.url_ = url;
   1198     this.isUnresolved_ = opt_isUnresolved;
   1199 
   1200     this.lineToBreakpointInfo_ = {};
   1201 };
   1202 
   1203 
   1204 /**
   1205  * @return {number}
   1206  */
   1207 devtools.ScriptInfo.prototype.getLineOffset = function()
   1208 {
   1209     return this.lineOffset_;
   1210 };
   1211 
   1212 
   1213 /**
   1214  * @return {string}
   1215  */
   1216 devtools.ScriptInfo.prototype.getContextType = function()
   1217 {
   1218     return this.contextType_;
   1219 };
   1220 
   1221 
   1222 /**
   1223  * @return {?string}
   1224  */
   1225 devtools.ScriptInfo.prototype.getUrl = function()
   1226 {
   1227     return this.url_;
   1228 };
   1229 
   1230 
   1231 /**
   1232  * @return {?bool}
   1233  */
   1234 devtools.ScriptInfo.prototype.isUnresolved = function()
   1235 {
   1236     return this.isUnresolved_;
   1237 };
   1238 
   1239 
   1240 /**
   1241  * @param {number} line 0-based line number in the script.
   1242  * @return {?devtools.BreakpointInfo} Information on a breakpoint at the
   1243  *     specified line in the script or undefined if there is no breakpoint at
   1244  *     that line.
   1245  */
   1246 devtools.ScriptInfo.prototype.getBreakpointInfo = function(line)
   1247 {
   1248     return this.lineToBreakpointInfo_[line];
   1249 };
   1250 
   1251 
   1252 /**
   1253  * Adds breakpoint info to the script.
   1254  * @param {devtools.BreakpointInfo} breakpoint
   1255  */
   1256 devtools.ScriptInfo.prototype.addBreakpointInfo = function(breakpoint)
   1257 {
   1258     this.lineToBreakpointInfo_[breakpoint.getLine()] = breakpoint;
   1259 };
   1260 
   1261 
   1262 /**
   1263  * @param {devtools.BreakpointInfo} breakpoint Breakpoint info to be removed.
   1264  */
   1265 devtools.ScriptInfo.prototype.removeBreakpointInfo = function(breakpoint)
   1266 {
   1267     var line = breakpoint.getLine();
   1268     delete this.lineToBreakpointInfo_[line];
   1269 };
   1270 
   1271 
   1272 
   1273 /**
   1274  * @param {number} line Breakpoint 0-based line number in the containing script.
   1275  * @constructor
   1276  */
   1277 devtools.BreakpointInfo = function(line)
   1278 {
   1279     this.line_ = line;
   1280     this.v8id_ = -1;
   1281     this.removed_ = false;
   1282 };
   1283 
   1284 
   1285 /**
   1286  * @return {number}
   1287  */
   1288 devtools.BreakpointInfo.prototype.getLine = function(n)
   1289 {
   1290     return this.line_;
   1291 };
   1292 
   1293 
   1294 /**
   1295  * @return {number} Unique identifier of this breakpoint in the v8 debugger.
   1296  */
   1297 devtools.BreakpointInfo.prototype.getV8Id = function(n)
   1298 {
   1299     return this.v8id_;
   1300 };
   1301 
   1302 
   1303 /**
   1304  * Sets id of this breakpoint in the v8 debugger.
   1305  * @param {number} id
   1306  */
   1307 devtools.BreakpointInfo.prototype.setV8Id = function(id)
   1308 {
   1309     this.v8id_ = id;
   1310 };
   1311 
   1312 
   1313 /**
   1314  * Marks this breakpoint as removed from the  front-end.
   1315  */
   1316 devtools.BreakpointInfo.prototype.markAsRemoved = function()
   1317 {
   1318     this.removed_ = true;
   1319 };
   1320 
   1321 
   1322 /**
   1323  * @return {boolean} Whether this breakpoint has been removed from the
   1324  *     front-end.
   1325  */
   1326 devtools.BreakpointInfo.prototype.isRemoved = function()
   1327 {
   1328     return this.removed_;
   1329 };
   1330 
   1331 
   1332 /**
   1333  * Call stack frame data.
   1334  * @param {string} id CallFrame id.
   1335  * @param {string} type CallFrame type.
   1336  * @param {string} functionName CallFrame type.
   1337  * @param {string} sourceID Source id.
   1338  * @param {number} line Source line.
   1339  * @param {Array.<Object>} scopeChain Array of scoped objects.
   1340  * @construnctor
   1341  */
   1342 devtools.CallFrame = function(id, type, functionName, sourceID, line, scopeChain)
   1343 {
   1344     this.id = id;
   1345     this.type = type;
   1346     this.functionName = functionName;
   1347     this.sourceID = sourceID;
   1348     this.line = line;
   1349     this.scopeChain = scopeChain;
   1350 };
   1351 
   1352 
   1353 /**
   1354  * This method issues asynchronous evaluate request, reports result to the
   1355  * callback.
   1356  * @param {string} expression An expression to be evaluated in the context of
   1357  *     this call frame.
   1358  * @param {function(Object):undefined} callback Callback to report result to.
   1359  */
   1360 devtools.CallFrame.prototype.evaluate_ = function(expression, callback)
   1361 {
   1362     devtools.tools.getDebuggerAgent().requestEvaluate({
   1363             "expression": expression,
   1364             "frame": this.id,
   1365             "global": false,
   1366             "disable_break": false,
   1367             "compactFormat": true
   1368         },
   1369         function(response) {
   1370             var result = {};
   1371             if (response.isSuccess())
   1372                 result.value = devtools.DebuggerAgent.formatObjectProxy_(response.getBody());
   1373             else {
   1374                 result.value = response.getMessage();
   1375                 result.isException = true;
   1376             }
   1377             callback(result);
   1378         });
   1379 };
   1380 
   1381 
   1382 /**
   1383  * JSON based commands sent to v8 debugger.
   1384  * @param {string} command Name of the command to execute.
   1385  * @param {Object} opt_arguments Command-specific arguments map.
   1386  * @constructor
   1387  */
   1388 devtools.DebugCommand = function(command, opt_arguments)
   1389 {
   1390     this.command_ = command;
   1391     this.type_ = "request";
   1392     this.seq_ = ++devtools.DebugCommand.nextSeq_;
   1393     if (opt_arguments)
   1394         this.arguments_ = opt_arguments;
   1395 };
   1396 
   1397 
   1398 /**
   1399  * Next unique number to be used as debugger request sequence number.
   1400  * @type {number}
   1401  */
   1402 devtools.DebugCommand.nextSeq_ = 1;
   1403 
   1404 
   1405 /**
   1406  * @return {number}
   1407  */
   1408 devtools.DebugCommand.prototype.getSequenceNumber = function()
   1409 {
   1410     return this.seq_;
   1411 };
   1412 
   1413 
   1414 /**
   1415  * @return {string}
   1416  */
   1417 devtools.DebugCommand.prototype.toJSONProtocol = function()
   1418 {
   1419     var json = {
   1420         "seq": this.seq_,
   1421         "type": this.type_,
   1422         "command": this.command_
   1423     }
   1424     if (this.arguments_)
   1425         json.arguments = this.arguments_;
   1426     return JSON.stringify(json);
   1427 };
   1428 
   1429 
   1430 /**
   1431  * JSON messages sent from v8 debugger. See protocol definition for more
   1432  * details: http://code.google.com/p/v8/wiki/DebuggerProtocol
   1433  * @param {string} msg Raw protocol packet as JSON string.
   1434  * @constructor
   1435  */
   1436 devtools.DebuggerMessage = function(msg)
   1437 {
   1438     this.packet_ = JSON.parse(msg);
   1439     this.refs_ = [];
   1440     if (this.packet_.refs) {
   1441         for (var i = 0; i < this.packet_.refs.length; i++)
   1442             this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i];
   1443     }
   1444 };
   1445 
   1446 
   1447 /**
   1448  * @return {string} The packet type.
   1449  */
   1450 devtools.DebuggerMessage.prototype.getType = function()
   1451 {
   1452     return this.packet_.type;
   1453 };
   1454 
   1455 
   1456 /**
   1457  * @return {?string} The packet event if the message is an event.
   1458  */
   1459 devtools.DebuggerMessage.prototype.getEvent = function()
   1460 {
   1461     return this.packet_.event;
   1462 };
   1463 
   1464 
   1465 /**
   1466  * @return {?string} The packet command if the message is a response to a
   1467  *     command.
   1468  */
   1469 devtools.DebuggerMessage.prototype.getCommand = function()
   1470 {
   1471     return this.packet_.command;
   1472 };
   1473 
   1474 
   1475 /**
   1476  * @return {number} The packet request sequence.
   1477  */
   1478 devtools.DebuggerMessage.prototype.getRequestSeq = function()
   1479 {
   1480     return this.packet_.request_seq;
   1481 };
   1482 
   1483 
   1484 /**
   1485  * @return {number} Whether the v8 is running after processing the request.
   1486  */
   1487 devtools.DebuggerMessage.prototype.isRunning = function()
   1488 {
   1489     return this.packet_.running ? true : false;
   1490 };
   1491 
   1492 
   1493 /**
   1494  * @return {boolean} Whether the request succeeded.
   1495  */
   1496 devtools.DebuggerMessage.prototype.isSuccess = function()
   1497 {
   1498     return this.packet_.success ? true : false;
   1499 };
   1500 
   1501 
   1502 /**
   1503  * @return {string}
   1504  */
   1505 devtools.DebuggerMessage.prototype.getMessage = function()
   1506 {
   1507     return this.packet_.message;
   1508 };
   1509 
   1510 
   1511 /**
   1512  * @return {Object} Parsed message body json.
   1513  */
   1514 devtools.DebuggerMessage.prototype.getBody = function()
   1515 {
   1516     return this.packet_.body;
   1517 };
   1518 
   1519 
   1520 /**
   1521  * @param {number} handle Object handle.
   1522  * @return {?Object} Returns the object with the handle if it was sent in this
   1523  *    message(some objects referenced by handles may be missing in the message).
   1524  */
   1525 devtools.DebuggerMessage.prototype.lookup = function(handle)
   1526 {
   1527     return this.refs_[handle];
   1528 };
   1529