Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // Default number of frames to include in the response to backtrace request.
     29 const kDefaultBacktraceLength = 10;
     30 
     31 const Debug = {};
     32 
     33 // Regular expression to skip "crud" at the beginning of a source line which is
     34 // not really code. Currently the regular expression matches whitespace and
     35 // comments.
     36 const sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
     37 
     38 // Debug events which can occour in the V8 JavaScript engine. These originate
     39 // from the API include file debug.h.
     40 Debug.DebugEvent = { Break: 1,
     41                      Exception: 2,
     42                      NewFunction: 3,
     43                      BeforeCompile: 4,
     44                      AfterCompile: 5,
     45                      ScriptCollected: 6 };
     46 
     47 // Types of exceptions that can be broken upon.
     48 Debug.ExceptionBreak = { Caught : 0,
     49                          Uncaught: 1 };
     50 
     51 // The different types of steps.
     52 Debug.StepAction = { StepOut: 0,
     53                      StepNext: 1,
     54                      StepIn: 2,
     55                      StepMin: 3,
     56                      StepInMin: 4 };
     57 
     58 // The different types of scripts matching enum ScriptType in objects.h.
     59 Debug.ScriptType = { Native: 0,
     60                      Extension: 1,
     61                      Normal: 2 };
     62 
     63 // The different types of script compilations matching enum
     64 // Script::CompilationType in objects.h.
     65 Debug.ScriptCompilationType = { Host: 0,
     66                                 Eval: 1,
     67                                 JSON: 2 };
     68 
     69 // The different script break point types.
     70 Debug.ScriptBreakPointType = { ScriptId: 0,
     71                                ScriptName: 1 };
     72 
     73 function ScriptTypeFlag(type) {
     74   return (1 << type);
     75 }
     76 
     77 // Globals.
     78 var next_response_seq = 0;
     79 var next_break_point_number = 1;
     80 var break_points = [];
     81 var script_break_points = [];
     82 var debugger_flags = {
     83   breakPointsActive: {
     84     value: true,
     85     getValue: function() { return this.value; },
     86     setValue: function(value) {
     87       this.value = !!value;
     88       %SetDisableBreak(!this.value);
     89     }
     90   },
     91   breakOnCaughtException: {
     92     getValue: function() { return Debug.isBreakOnException(); },
     93     setValue: function(value) {
     94       if (value) {
     95         Debug.setBreakOnException();
     96       } else {
     97         Debug.clearBreakOnException();
     98       }
     99     }
    100   },
    101   breakOnUncaughtException: {
    102     getValue: function() { return Debug.isBreakOnUncaughtException(); },
    103     setValue: function(value) {
    104       if (value) {
    105         Debug.setBreakOnUncaughtException();
    106       } else {
    107         Debug.clearBreakOnUncaughtException();
    108       }
    109     }
    110   },
    111 };
    112 var lol_is_enabled = %HasLOLEnabled();
    113 
    114 
    115 // Create a new break point object and add it to the list of break points.
    116 function MakeBreakPoint(source_position, opt_script_break_point) {
    117   var break_point = new BreakPoint(source_position, opt_script_break_point);
    118   break_points.push(break_point);
    119   return break_point;
    120 }
    121 
    122 
    123 // Object representing a break point.
    124 // NOTE: This object does not have a reference to the function having break
    125 // point as this would cause function not to be garbage collected when it is
    126 // not used any more. We do not want break points to keep functions alive.
    127 function BreakPoint(source_position, opt_script_break_point) {
    128   this.source_position_ = source_position;
    129   if (opt_script_break_point) {
    130     this.script_break_point_ = opt_script_break_point;
    131   } else {
    132     this.number_ = next_break_point_number++;
    133   }
    134   this.hit_count_ = 0;
    135   this.active_ = true;
    136   this.condition_ = null;
    137   this.ignoreCount_ = 0;
    138 }
    139 
    140 
    141 BreakPoint.prototype.number = function() {
    142   return this.number_;
    143 };
    144 
    145 
    146 BreakPoint.prototype.func = function() {
    147   return this.func_;
    148 };
    149 
    150 
    151 BreakPoint.prototype.source_position = function() {
    152   return this.source_position_;
    153 };
    154 
    155 
    156 BreakPoint.prototype.hit_count = function() {
    157   return this.hit_count_;
    158 };
    159 
    160 
    161 BreakPoint.prototype.active = function() {
    162   if (this.script_break_point()) {
    163     return this.script_break_point().active();
    164   }
    165   return this.active_;
    166 };
    167 
    168 
    169 BreakPoint.prototype.condition = function() {
    170   if (this.script_break_point() && this.script_break_point().condition()) {
    171     return this.script_break_point().condition();
    172   }
    173   return this.condition_;
    174 };
    175 
    176 
    177 BreakPoint.prototype.ignoreCount = function() {
    178   return this.ignoreCount_;
    179 };
    180 
    181 
    182 BreakPoint.prototype.script_break_point = function() {
    183   return this.script_break_point_;
    184 };
    185 
    186 
    187 BreakPoint.prototype.enable = function() {
    188   this.active_ = true;
    189 };
    190 
    191 
    192 BreakPoint.prototype.disable = function() {
    193   this.active_ = false;
    194 };
    195 
    196 
    197 BreakPoint.prototype.setCondition = function(condition) {
    198   this.condition_ = condition;
    199 };
    200 
    201 
    202 BreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
    203   this.ignoreCount_ = ignoreCount;
    204 };
    205 
    206 
    207 BreakPoint.prototype.isTriggered = function(exec_state) {
    208   // Break point not active - not triggered.
    209   if (!this.active()) return false;
    210 
    211   // Check for conditional break point.
    212   if (this.condition()) {
    213     // If break point has condition try to evaluate it in the top frame.
    214     try {
    215       var mirror = exec_state.frame(0).evaluate(this.condition());
    216       // If no sensible mirror or non true value break point not triggered.
    217       if (!(mirror instanceof ValueMirror) || !%ToBoolean(mirror.value_)) {
    218         return false;
    219       }
    220     } catch (e) {
    221       // Exception evaluating condition counts as not triggered.
    222       return false;
    223     }
    224   }
    225 
    226   // Update the hit count.
    227   this.hit_count_++;
    228   if (this.script_break_point_) {
    229     this.script_break_point_.hit_count_++;
    230   }
    231 
    232   // If the break point has an ignore count it is not triggered.
    233   if (this.ignoreCount_ > 0) {
    234     this.ignoreCount_--;
    235     return false;
    236   }
    237 
    238   // Break point triggered.
    239   return true;
    240 };
    241 
    242 
    243 // Function called from the runtime when a break point is hit. Returns true if
    244 // the break point is triggered and supposed to break execution.
    245 function IsBreakPointTriggered(break_id, break_point) {
    246   return break_point.isTriggered(MakeExecutionState(break_id));
    247 }
    248 
    249 
    250 // Object representing a script break point. The script is referenced by its
    251 // script name or script id and the break point is represented as line and
    252 // column.
    253 function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
    254                           opt_groupId) {
    255   this.type_ = type;
    256   if (type == Debug.ScriptBreakPointType.ScriptId) {
    257     this.script_id_ = script_id_or_name;
    258   } else {  // type == Debug.ScriptBreakPointType.ScriptName
    259     this.script_name_ = script_id_or_name;
    260   }
    261   this.line_ = opt_line || 0;
    262   this.column_ = opt_column;
    263   this.groupId_ = opt_groupId;
    264   this.hit_count_ = 0;
    265   this.active_ = true;
    266   this.condition_ = null;
    267   this.ignoreCount_ = 0;
    268   this.break_points_ = [];
    269 }
    270 
    271 
    272 //Creates a clone of script breakpoint that is linked to another script.
    273 ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) {
    274   var copy = new ScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
    275       other_script.id, this.line_, this.column_, this.groupId_);
    276   copy.number_ = next_break_point_number++;
    277   script_break_points.push(copy);
    278 
    279   copy.hit_count_ = this.hit_count_;
    280   copy.active_ = this.active_;
    281   copy.condition_ = this.condition_;
    282   copy.ignoreCount_ = this.ignoreCount_;
    283   return copy;
    284 }
    285 
    286 
    287 ScriptBreakPoint.prototype.number = function() {
    288   return this.number_;
    289 };
    290 
    291 
    292 ScriptBreakPoint.prototype.groupId = function() {
    293   return this.groupId_;
    294 };
    295 
    296 
    297 ScriptBreakPoint.prototype.type = function() {
    298   return this.type_;
    299 };
    300 
    301 
    302 ScriptBreakPoint.prototype.script_id = function() {
    303   return this.script_id_;
    304 };
    305 
    306 
    307 ScriptBreakPoint.prototype.script_name = function() {
    308   return this.script_name_;
    309 };
    310 
    311 
    312 ScriptBreakPoint.prototype.line = function() {
    313   return this.line_;
    314 };
    315 
    316 
    317 ScriptBreakPoint.prototype.column = function() {
    318   return this.column_;
    319 };
    320 
    321 
    322 ScriptBreakPoint.prototype.actual_locations = function() {
    323   var locations = [];
    324   for (var i = 0; i < this.break_points_.length; i++) {
    325     locations.push(this.break_points_[i].actual_location);
    326   }
    327   return locations;
    328 }
    329 
    330 
    331 ScriptBreakPoint.prototype.update_positions = function(line, column) {
    332   this.line_ = line;
    333   this.column_ = column;
    334 }
    335 
    336 
    337 ScriptBreakPoint.prototype.hit_count = function() {
    338   return this.hit_count_;
    339 };
    340 
    341 
    342 ScriptBreakPoint.prototype.active = function() {
    343   return this.active_;
    344 };
    345 
    346 
    347 ScriptBreakPoint.prototype.condition = function() {
    348   return this.condition_;
    349 };
    350 
    351 
    352 ScriptBreakPoint.prototype.ignoreCount = function() {
    353   return this.ignoreCount_;
    354 };
    355 
    356 
    357 ScriptBreakPoint.prototype.enable = function() {
    358   this.active_ = true;
    359 };
    360 
    361 
    362 ScriptBreakPoint.prototype.disable = function() {
    363   this.active_ = false;
    364 };
    365 
    366 
    367 ScriptBreakPoint.prototype.setCondition = function(condition) {
    368   this.condition_ = condition;
    369 };
    370 
    371 
    372 ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
    373   this.ignoreCount_ = ignoreCount;
    374 
    375   // Set ignore count on all break points created from this script break point.
    376   for (var i = 0; i < this.break_points_.length; i++) {
    377     this.break_points_[i].setIgnoreCount(ignoreCount);
    378   }
    379 };
    380 
    381 
    382 // Check whether a script matches this script break point. Currently this is
    383 // only based on script name.
    384 ScriptBreakPoint.prototype.matchesScript = function(script) {
    385   if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
    386     return this.script_id_ == script.id;
    387   } else {  // this.type_ == Debug.ScriptBreakPointType.ScriptName
    388     return this.script_name_ == script.nameOrSourceURL() &&
    389            script.line_offset <= this.line_  &&
    390            this.line_ < script.line_offset + script.lineCount();
    391   }
    392 };
    393 
    394 
    395 // Set the script break point in a script.
    396 ScriptBreakPoint.prototype.set = function (script) {
    397   var column = this.column();
    398   var line = this.line();
    399   // If the column is undefined the break is on the line. To help locate the
    400   // first piece of breakable code on the line try to find the column on the
    401   // line which contains some source.
    402   if (IS_UNDEFINED(column)) {
    403     var source_line = script.sourceLine(this.line());
    404 
    405     // Allocate array for caching the columns where the actual source starts.
    406     if (!script.sourceColumnStart_) {
    407       script.sourceColumnStart_ = new Array(script.lineCount());
    408     }
    409 
    410     // Fill cache if needed and get column where the actual source starts.
    411     if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
    412       script.sourceColumnStart_[line] =
    413           source_line.match(sourceLineBeginningSkip)[0].length;
    414     }
    415     column = script.sourceColumnStart_[line];
    416   }
    417 
    418   // Convert the line and column into an absolute position within the script.
    419   var position = Debug.findScriptSourcePosition(script, this.line(), column);
    420 
    421   // If the position is not found in the script (the script might be shorter
    422   // than it used to be) just ignore it.
    423   if (position === null) return;
    424 
    425   // Create a break point object and set the break point.
    426   break_point = MakeBreakPoint(position, this);
    427   break_point.setIgnoreCount(this.ignoreCount());
    428   var actual_position = %SetScriptBreakPoint(script, position, break_point);
    429   if (IS_UNDEFINED(actual_position)) {
    430     actual_position = position;
    431   }
    432   var actual_location = script.locationFromPosition(actual_position, true);
    433   break_point.actual_location = { line: actual_location.line,
    434                                   column: actual_location.column };
    435   this.break_points_.push(break_point);
    436   return break_point;
    437 };
    438 
    439 
    440 // Clear all the break points created from this script break point
    441 ScriptBreakPoint.prototype.clear = function () {
    442   var remaining_break_points = [];
    443   for (var i = 0; i < break_points.length; i++) {
    444     if (break_points[i].script_break_point() &&
    445         break_points[i].script_break_point() === this) {
    446       %ClearBreakPoint(break_points[i]);
    447     } else {
    448       remaining_break_points.push(break_points[i]);
    449     }
    450   }
    451   break_points = remaining_break_points;
    452   this.break_points_ = [];
    453 };
    454 
    455 
    456 // Function called from runtime when a new script is compiled to set any script
    457 // break points set in this script.
    458 function UpdateScriptBreakPoints(script) {
    459   for (var i = 0; i < script_break_points.length; i++) {
    460     if (script_break_points[i].type() == Debug.ScriptBreakPointType.ScriptName &&
    461         script_break_points[i].matchesScript(script)) {
    462       script_break_points[i].set(script);
    463     }
    464   }
    465 }
    466 
    467 
    468 function GetScriptBreakPoints(script) {
    469   var result = [];
    470   for (var i = 0; i < script_break_points.length; i++) {
    471     if (script_break_points[i].matchesScript(script)) {
    472       result.push(script_break_points[i]);
    473     }
    474   }
    475   return result;
    476 }
    477 
    478 
    479 Debug.setListener = function(listener, opt_data) {
    480   if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
    481     throw new Error('Parameters have wrong types.');
    482   }
    483   %SetDebugEventListener(listener, opt_data);
    484 };
    485 
    486 
    487 Debug.breakExecution = function(f) {
    488   %Break();
    489 };
    490 
    491 Debug.breakLocations = function(f) {
    492   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    493   return %GetBreakLocations(f);
    494 };
    495 
    496 // Returns a Script object. If the parameter is a function the return value
    497 // is the script in which the function is defined. If the parameter is a string
    498 // the return value is the script for which the script name has that string
    499 // value.  If it is a regexp and there is a unique script whose name matches
    500 // we return that, otherwise undefined.
    501 Debug.findScript = function(func_or_script_name) {
    502   if (IS_FUNCTION(func_or_script_name)) {
    503     return %FunctionGetScript(func_or_script_name);
    504   } else if (IS_REGEXP(func_or_script_name)) {
    505     var scripts = Debug.scripts();
    506     var last_result = null;
    507     var result_count = 0;
    508     for (var i in scripts) {
    509       var script = scripts[i];
    510       if (func_or_script_name.test(script.name)) {
    511         last_result = script;
    512         result_count++;
    513       }
    514     }
    515     // Return the unique script matching the regexp.  If there are more
    516     // than one we don't return a value since there is no good way to
    517     // decide which one to return.  Returning a "random" one, say the
    518     // first, would introduce nondeterminism (or something close to it)
    519     // because the order is the heap iteration order.
    520     if (result_count == 1) {
    521       return last_result;
    522     } else {
    523       return undefined;
    524     }
    525   } else {
    526     return %GetScript(func_or_script_name);
    527   }
    528 };
    529 
    530 // Returns the script source. If the parameter is a function the return value
    531 // is the script source for the script in which the function is defined. If the
    532 // parameter is a string the return value is the script for which the script
    533 // name has that string value.
    534 Debug.scriptSource = function(func_or_script_name) {
    535   return this.findScript(func_or_script_name).source;
    536 };
    537 
    538 Debug.source = function(f) {
    539   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    540   return %FunctionGetSourceCode(f);
    541 };
    542 
    543 Debug.disassemble = function(f) {
    544   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    545   return %DebugDisassembleFunction(f);
    546 };
    547 
    548 Debug.disassembleConstructor = function(f) {
    549   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    550   return %DebugDisassembleConstructor(f);
    551 };
    552 
    553 Debug.ExecuteInDebugContext = function(f, without_debugger) {
    554   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    555   return %ExecuteInDebugContext(f, !!without_debugger);
    556 };
    557 
    558 Debug.sourcePosition = function(f) {
    559   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    560   return %FunctionGetScriptSourcePosition(f);
    561 };
    562 
    563 
    564 Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
    565   var script = %FunctionGetScript(func);
    566   var script_offset = %FunctionGetScriptSourcePosition(func);
    567   return script.locationFromLine(opt_line, opt_column, script_offset);
    568 }
    569 
    570 
    571 // Returns the character position in a script based on a line number and an
    572 // optional position within that line.
    573 Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
    574   var location = script.locationFromLine(opt_line, opt_column);
    575   return location ? location.position : null;
    576 }
    577 
    578 
    579 Debug.findBreakPoint = function(break_point_number, remove) {
    580   var break_point;
    581   for (var i = 0; i < break_points.length; i++) {
    582     if (break_points[i].number() == break_point_number) {
    583       break_point = break_points[i];
    584       // Remove the break point from the list if requested.
    585       if (remove) {
    586         break_points.splice(i, 1);
    587       }
    588       break;
    589     }
    590   }
    591   if (break_point) {
    592     return break_point;
    593   } else {
    594     return this.findScriptBreakPoint(break_point_number, remove);
    595   }
    596 };
    597 
    598 Debug.findBreakPointActualLocations = function(break_point_number) {
    599   for (var i = 0; i < script_break_points.length; i++) {
    600     if (script_break_points[i].number() == break_point_number) {
    601       return script_break_points[i].actual_locations();
    602     }
    603   }
    604   for (var i = 0; i < break_points.length; i++) {
    605     if (break_points[i].number() == break_point_number) {
    606       return [break_points[i].actual_location];
    607     }
    608   }
    609   return [];
    610 }
    611 
    612 Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
    613   if (!IS_FUNCTION(func)) throw new Error('Parameters have wrong types.');
    614   // Break points in API functions are not supported.
    615   if (%FunctionIsAPIFunction(func)) {
    616     throw new Error('Cannot set break point in native code.');
    617   }
    618   // Find source position relative to start of the function
    619   var break_position =
    620       this.findFunctionSourceLocation(func, opt_line, opt_column).position;
    621   var source_position = break_position - this.sourcePosition(func);
    622   // Find the script for the function.
    623   var script = %FunctionGetScript(func);
    624   // Break in builtin JavaScript code is not supported.
    625   if (script.type == Debug.ScriptType.Native) {
    626     throw new Error('Cannot set break point in native code.');
    627   }
    628   // If the script for the function has a name convert this to a script break
    629   // point.
    630   if (script && script.id) {
    631     // Adjust the source position to be script relative.
    632     source_position += %FunctionGetScriptSourcePosition(func);
    633     // Find line and column for the position in the script and set a script
    634     // break point from that.
    635     var location = script.locationFromPosition(source_position, false);
    636     return this.setScriptBreakPointById(script.id,
    637                                         location.line, location.column,
    638                                         opt_condition);
    639   } else {
    640     // Set a break point directly on the function.
    641     var break_point = MakeBreakPoint(source_position);
    642     var actual_position =
    643         %SetFunctionBreakPoint(func, source_position, break_point);
    644     actual_position += this.sourcePosition(func);
    645     var actual_location = script.locationFromPosition(actual_position, true);
    646     break_point.actual_location = { line: actual_location.line,
    647                                     column: actual_location.column };
    648     break_point.setCondition(opt_condition);
    649     return break_point.number();
    650   }
    651 };
    652 
    653 
    654 Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
    655                                                     condition, enabled)
    656 {
    657   break_point = MakeBreakPoint(position);
    658   break_point.setCondition(condition);
    659   if (!enabled)
    660     break_point.disable();
    661   var scripts = this.scripts();
    662   for (var i = 0; i < scripts.length; i++) {
    663     if (script_id == scripts[i].id) {
    664       break_point.actual_position = %SetScriptBreakPoint(scripts[i], position,
    665                                                          break_point);
    666       break;
    667     }
    668   }
    669   return break_point;
    670 };
    671 
    672 
    673 Debug.enableBreakPoint = function(break_point_number) {
    674   var break_point = this.findBreakPoint(break_point_number, false);
    675   // Only enable if the breakpoint hasn't been deleted:
    676   if (break_point) {
    677     break_point.enable();
    678   }
    679 };
    680 
    681 
    682 Debug.disableBreakPoint = function(break_point_number) {
    683   var break_point = this.findBreakPoint(break_point_number, false);
    684   // Only enable if the breakpoint hasn't been deleted:
    685   if (break_point) {
    686     break_point.disable();
    687   }
    688 };
    689 
    690 
    691 Debug.changeBreakPointCondition = function(break_point_number, condition) {
    692   var break_point = this.findBreakPoint(break_point_number, false);
    693   break_point.setCondition(condition);
    694 };
    695 
    696 
    697 Debug.changeBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
    698   if (ignoreCount < 0) {
    699     throw new Error('Invalid argument');
    700   }
    701   var break_point = this.findBreakPoint(break_point_number, false);
    702   break_point.setIgnoreCount(ignoreCount);
    703 };
    704 
    705 
    706 Debug.clearBreakPoint = function(break_point_number) {
    707   var break_point = this.findBreakPoint(break_point_number, true);
    708   if (break_point) {
    709     return %ClearBreakPoint(break_point);
    710   } else {
    711     break_point = this.findScriptBreakPoint(break_point_number, true);
    712     if (!break_point) {
    713       throw new Error('Invalid breakpoint');
    714     }
    715   }
    716 };
    717 
    718 
    719 Debug.clearAllBreakPoints = function() {
    720   for (var i = 0; i < break_points.length; i++) {
    721     break_point = break_points[i];
    722     %ClearBreakPoint(break_point);
    723   }
    724   break_points = [];
    725 };
    726 
    727 
    728 Debug.disableAllBreakPoints = function() {
    729   // Disable all user defined breakpoints:
    730   for (var i = 1; i < next_break_point_number; i++) {
    731     Debug.disableBreakPoint(i);
    732   }
    733   // Disable all exception breakpoints:
    734   %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
    735   %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
    736 };
    737 
    738 
    739 Debug.findScriptBreakPoint = function(break_point_number, remove) {
    740   var script_break_point;
    741   for (var i = 0; i < script_break_points.length; i++) {
    742     if (script_break_points[i].number() == break_point_number) {
    743       script_break_point = script_break_points[i];
    744       // Remove the break point from the list if requested.
    745       if (remove) {
    746         script_break_point.clear();
    747         script_break_points.splice(i,1);
    748       }
    749       break;
    750     }
    751   }
    752   return script_break_point;
    753 }
    754 
    755 
    756 // Sets a breakpoint in a script identified through id or name at the
    757 // specified source line and column within that line.
    758 Debug.setScriptBreakPoint = function(type, script_id_or_name,
    759                                      opt_line, opt_column, opt_condition,
    760                                      opt_groupId) {
    761   // Create script break point object.
    762   var script_break_point =
    763       new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
    764                            opt_groupId);
    765 
    766   // Assign number to the new script break point and add it.
    767   script_break_point.number_ = next_break_point_number++;
    768   script_break_point.setCondition(opt_condition);
    769   script_break_points.push(script_break_point);
    770 
    771   // Run through all scripts to see if this script break point matches any
    772   // loaded scripts.
    773   var scripts = this.scripts();
    774   for (var i = 0; i < scripts.length; i++) {
    775     if (script_break_point.matchesScript(scripts[i])) {
    776       script_break_point.set(scripts[i]);
    777     }
    778   }
    779 
    780   return script_break_point.number();
    781 }
    782 
    783 
    784 Debug.setScriptBreakPointById = function(script_id,
    785                                          opt_line, opt_column,
    786                                          opt_condition, opt_groupId) {
    787   return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
    788                                   script_id, opt_line, opt_column,
    789                                   opt_condition, opt_groupId);
    790 }
    791 
    792 
    793 Debug.setScriptBreakPointByName = function(script_name,
    794                                            opt_line, opt_column,
    795                                            opt_condition, opt_groupId) {
    796   return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
    797                                   script_name, opt_line, opt_column,
    798                                   opt_condition, opt_groupId);
    799 }
    800 
    801 
    802 Debug.enableScriptBreakPoint = function(break_point_number) {
    803   var script_break_point = this.findScriptBreakPoint(break_point_number, false);
    804   script_break_point.enable();
    805 };
    806 
    807 
    808 Debug.disableScriptBreakPoint = function(break_point_number) {
    809   var script_break_point = this.findScriptBreakPoint(break_point_number, false);
    810   script_break_point.disable();
    811 };
    812 
    813 
    814 Debug.changeScriptBreakPointCondition = function(break_point_number, condition) {
    815   var script_break_point = this.findScriptBreakPoint(break_point_number, false);
    816   script_break_point.setCondition(condition);
    817 };
    818 
    819 
    820 Debug.changeScriptBreakPointIgnoreCount = function(break_point_number, ignoreCount) {
    821   if (ignoreCount < 0) {
    822     throw new Error('Invalid argument');
    823   }
    824   var script_break_point = this.findScriptBreakPoint(break_point_number, false);
    825   script_break_point.setIgnoreCount(ignoreCount);
    826 };
    827 
    828 
    829 Debug.scriptBreakPoints = function() {
    830   return script_break_points;
    831 }
    832 
    833 
    834 Debug.clearStepping = function() {
    835   %ClearStepping();
    836 }
    837 
    838 Debug.setBreakOnException = function() {
    839   return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
    840 };
    841 
    842 Debug.clearBreakOnException = function() {
    843   return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
    844 };
    845 
    846 Debug.isBreakOnException = function() {
    847   return !!%IsBreakOnException(Debug.ExceptionBreak.Caught);
    848 };
    849 
    850 Debug.setBreakOnUncaughtException = function() {
    851   return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
    852 };
    853 
    854 Debug.clearBreakOnUncaughtException = function() {
    855   return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
    856 };
    857 
    858 Debug.isBreakOnUncaughtException = function() {
    859   return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
    860 };
    861 
    862 Debug.showBreakPoints = function(f, full) {
    863   if (!IS_FUNCTION(f)) throw new Error('Parameters have wrong types.');
    864   var source = full ? this.scriptSource(f) : this.source(f);
    865   var offset = full ? this.sourcePosition(f) : 0;
    866   var locations = this.breakLocations(f);
    867   if (!locations) return source;
    868   locations.sort(function(x, y) { return x - y; });
    869   var result = "";
    870   var prev_pos = 0;
    871   var pos;
    872   for (var i = 0; i < locations.length; i++) {
    873     pos = locations[i] - offset;
    874     result += source.slice(prev_pos, pos);
    875     result += "[B" + i + "]";
    876     prev_pos = pos;
    877   }
    878   pos = source.length;
    879   result += source.substring(prev_pos, pos);
    880   return result;
    881 };
    882 
    883 
    884 // Get all the scripts currently loaded. Locating all the scripts is based on
    885 // scanning the heap.
    886 Debug.scripts = function() {
    887   // Collect all scripts in the heap.
    888   return %DebugGetLoadedScripts();
    889 };
    890 
    891 
    892 Debug.debuggerFlags = function() {
    893   return debugger_flags;
    894 };
    895 
    896 Debug.MakeMirror = MakeMirror;
    897 
    898 function MakeExecutionState(break_id) {
    899   return new ExecutionState(break_id);
    900 }
    901 
    902 function ExecutionState(break_id) {
    903   this.break_id = break_id;
    904   this.selected_frame = 0;
    905 }
    906 
    907 ExecutionState.prototype.prepareStep = function(opt_action, opt_count) {
    908   var action = Debug.StepAction.StepIn;
    909   if (!IS_UNDEFINED(opt_action)) action = %ToNumber(opt_action);
    910   var count = opt_count ? %ToNumber(opt_count) : 1;
    911 
    912   return %PrepareStep(this.break_id, action, count);
    913 }
    914 
    915 ExecutionState.prototype.evaluateGlobal = function(source, disable_break,
    916     opt_additional_context) {
    917   return MakeMirror(%DebugEvaluateGlobal(this.break_id, source,
    918                                          Boolean(disable_break),
    919                                          opt_additional_context));
    920 };
    921 
    922 ExecutionState.prototype.frameCount = function() {
    923   return %GetFrameCount(this.break_id);
    924 };
    925 
    926 ExecutionState.prototype.threadCount = function() {
    927   return %GetThreadCount(this.break_id);
    928 };
    929 
    930 ExecutionState.prototype.frame = function(opt_index) {
    931   // If no index supplied return the selected frame.
    932   if (opt_index == null) opt_index = this.selected_frame;
    933   if (opt_index < 0 || opt_index >= this.frameCount())
    934     throw new Error('Illegal frame index.');
    935   return new FrameMirror(this.break_id, opt_index);
    936 };
    937 
    938 ExecutionState.prototype.setSelectedFrame = function(index) {
    939   var i = %ToNumber(index);
    940   if (i < 0 || i >= this.frameCount()) throw new Error('Illegal frame index.');
    941   this.selected_frame = i;
    942 };
    943 
    944 ExecutionState.prototype.selectedFrame = function() {
    945   return this.selected_frame;
    946 };
    947 
    948 ExecutionState.prototype.debugCommandProcessor = function(opt_is_running) {
    949   return new DebugCommandProcessor(this, opt_is_running);
    950 };
    951 
    952 
    953 function MakeBreakEvent(exec_state, break_points_hit) {
    954   return new BreakEvent(exec_state, break_points_hit);
    955 }
    956 
    957 
    958 function BreakEvent(exec_state, break_points_hit) {
    959   this.exec_state_ = exec_state;
    960   this.break_points_hit_ = break_points_hit;
    961 }
    962 
    963 
    964 BreakEvent.prototype.executionState = function() {
    965   return this.exec_state_;
    966 };
    967 
    968 
    969 BreakEvent.prototype.eventType = function() {
    970   return Debug.DebugEvent.Break;
    971 };
    972 
    973 
    974 BreakEvent.prototype.func = function() {
    975   return this.exec_state_.frame(0).func();
    976 };
    977 
    978 
    979 BreakEvent.prototype.sourceLine = function() {
    980   return this.exec_state_.frame(0).sourceLine();
    981 };
    982 
    983 
    984 BreakEvent.prototype.sourceColumn = function() {
    985   return this.exec_state_.frame(0).sourceColumn();
    986 };
    987 
    988 
    989 BreakEvent.prototype.sourceLineText = function() {
    990   return this.exec_state_.frame(0).sourceLineText();
    991 };
    992 
    993 
    994 BreakEvent.prototype.breakPointsHit = function() {
    995   return this.break_points_hit_;
    996 };
    997 
    998 
    999 BreakEvent.prototype.toJSONProtocol = function() {
   1000   var o = { seq: next_response_seq++,
   1001             type: "event",
   1002             event: "break",
   1003             body: { invocationText: this.exec_state_.frame(0).invocationText(),
   1004                   }
   1005           };
   1006 
   1007   // Add script related information to the event if available.
   1008   var script = this.func().script();
   1009   if (script) {
   1010     o.body.sourceLine = this.sourceLine(),
   1011     o.body.sourceColumn = this.sourceColumn(),
   1012     o.body.sourceLineText = this.sourceLineText(),
   1013     o.body.script = MakeScriptObject_(script, false);
   1014   }
   1015 
   1016   // Add an Array of break points hit if any.
   1017   if (this.breakPointsHit()) {
   1018     o.body.breakpoints = [];
   1019     for (var i = 0; i < this.breakPointsHit().length; i++) {
   1020       // Find the break point number. For break points originating from a
   1021       // script break point supply the script break point number.
   1022       var breakpoint = this.breakPointsHit()[i];
   1023       var script_break_point = breakpoint.script_break_point();
   1024       var number;
   1025       if (script_break_point) {
   1026         number = script_break_point.number();
   1027       } else {
   1028         number = breakpoint.number();
   1029       }
   1030       o.body.breakpoints.push(number);
   1031     }
   1032   }
   1033   return JSON.stringify(ObjectToProtocolObject_(o));
   1034 };
   1035 
   1036 
   1037 function MakeExceptionEvent(exec_state, exception, uncaught) {
   1038   return new ExceptionEvent(exec_state, exception, uncaught);
   1039 }
   1040 
   1041 
   1042 function ExceptionEvent(exec_state, exception, uncaught) {
   1043   this.exec_state_ = exec_state;
   1044   this.exception_ = exception;
   1045   this.uncaught_ = uncaught;
   1046 }
   1047 
   1048 
   1049 ExceptionEvent.prototype.executionState = function() {
   1050   return this.exec_state_;
   1051 };
   1052 
   1053 
   1054 ExceptionEvent.prototype.eventType = function() {
   1055   return Debug.DebugEvent.Exception;
   1056 };
   1057 
   1058 
   1059 ExceptionEvent.prototype.exception = function() {
   1060   return this.exception_;
   1061 }
   1062 
   1063 
   1064 ExceptionEvent.prototype.uncaught = function() {
   1065   return this.uncaught_;
   1066 }
   1067 
   1068 
   1069 ExceptionEvent.prototype.func = function() {
   1070   return this.exec_state_.frame(0).func();
   1071 };
   1072 
   1073 
   1074 ExceptionEvent.prototype.sourceLine = function() {
   1075   return this.exec_state_.frame(0).sourceLine();
   1076 };
   1077 
   1078 
   1079 ExceptionEvent.prototype.sourceColumn = function() {
   1080   return this.exec_state_.frame(0).sourceColumn();
   1081 };
   1082 
   1083 
   1084 ExceptionEvent.prototype.sourceLineText = function() {
   1085   return this.exec_state_.frame(0).sourceLineText();
   1086 };
   1087 
   1088 
   1089 ExceptionEvent.prototype.toJSONProtocol = function() {
   1090   var o = new ProtocolMessage();
   1091   o.event = "exception";
   1092   o.body = { uncaught: this.uncaught_,
   1093              exception: MakeMirror(this.exception_)
   1094            };
   1095 
   1096   // Exceptions might happen whithout any JavaScript frames.
   1097   if (this.exec_state_.frameCount() > 0) {
   1098     o.body.sourceLine = this.sourceLine();
   1099     o.body.sourceColumn = this.sourceColumn();
   1100     o.body.sourceLineText = this.sourceLineText();
   1101 
   1102     // Add script information to the event if available.
   1103     var script = this.func().script();
   1104     if (script) {
   1105       o.body.script = MakeScriptObject_(script, false);
   1106     }
   1107   } else {
   1108     o.body.sourceLine = -1;
   1109   }
   1110 
   1111   return o.toJSONProtocol();
   1112 };
   1113 
   1114 
   1115 function MakeCompileEvent(exec_state, script, before) {
   1116   return new CompileEvent(exec_state, script, before);
   1117 }
   1118 
   1119 
   1120 function CompileEvent(exec_state, script, before) {
   1121   this.exec_state_ = exec_state;
   1122   this.script_ = MakeMirror(script);
   1123   this.before_ = before;
   1124 }
   1125 
   1126 
   1127 CompileEvent.prototype.executionState = function() {
   1128   return this.exec_state_;
   1129 };
   1130 
   1131 
   1132 CompileEvent.prototype.eventType = function() {
   1133   if (this.before_) {
   1134     return Debug.DebugEvent.BeforeCompile;
   1135   } else {
   1136     return Debug.DebugEvent.AfterCompile;
   1137   }
   1138 };
   1139 
   1140 
   1141 CompileEvent.prototype.script = function() {
   1142   return this.script_;
   1143 };
   1144 
   1145 
   1146 CompileEvent.prototype.toJSONProtocol = function() {
   1147   var o = new ProtocolMessage();
   1148   o.running = true;
   1149   if (this.before_) {
   1150     o.event = "beforeCompile";
   1151   } else {
   1152     o.event = "afterCompile";
   1153   }
   1154   o.body = {};
   1155   o.body.script = this.script_;
   1156 
   1157   return o.toJSONProtocol();
   1158 }
   1159 
   1160 
   1161 function MakeNewFunctionEvent(func) {
   1162   return new NewFunctionEvent(func);
   1163 }
   1164 
   1165 
   1166 function NewFunctionEvent(func) {
   1167   this.func = func;
   1168 }
   1169 
   1170 
   1171 NewFunctionEvent.prototype.eventType = function() {
   1172   return Debug.DebugEvent.NewFunction;
   1173 };
   1174 
   1175 
   1176 NewFunctionEvent.prototype.name = function() {
   1177   return this.func.name;
   1178 };
   1179 
   1180 
   1181 NewFunctionEvent.prototype.setBreakPoint = function(p) {
   1182   Debug.setBreakPoint(this.func, p || 0);
   1183 };
   1184 
   1185 
   1186 function MakeScriptCollectedEvent(exec_state, id) {
   1187   return new ScriptCollectedEvent(exec_state, id);
   1188 }
   1189 
   1190 
   1191 function ScriptCollectedEvent(exec_state, id) {
   1192   this.exec_state_ = exec_state;
   1193   this.id_ = id;
   1194 }
   1195 
   1196 
   1197 ScriptCollectedEvent.prototype.id = function() {
   1198   return this.id_;
   1199 };
   1200 
   1201 
   1202 ScriptCollectedEvent.prototype.executionState = function() {
   1203   return this.exec_state_;
   1204 };
   1205 
   1206 
   1207 ScriptCollectedEvent.prototype.toJSONProtocol = function() {
   1208   var o = new ProtocolMessage();
   1209   o.running = true;
   1210   o.event = "scriptCollected";
   1211   o.body = {};
   1212   o.body.script = { id: this.id() };
   1213   return o.toJSONProtocol();
   1214 }
   1215 
   1216 
   1217 function MakeScriptObject_(script, include_source) {
   1218   var o = { id: script.id(),
   1219             name: script.name(),
   1220             lineOffset: script.lineOffset(),
   1221             columnOffset: script.columnOffset(),
   1222             lineCount: script.lineCount(),
   1223           };
   1224   if (!IS_UNDEFINED(script.data())) {
   1225     o.data = script.data();
   1226   }
   1227   if (include_source) {
   1228     o.source = script.source();
   1229   }
   1230   return o;
   1231 };
   1232 
   1233 
   1234 function DebugCommandProcessor(exec_state, opt_is_running) {
   1235   this.exec_state_ = exec_state;
   1236   this.running_ = opt_is_running || false;
   1237 };
   1238 
   1239 
   1240 DebugCommandProcessor.prototype.processDebugRequest = function (request) {
   1241   return this.processDebugJSONRequest(request);
   1242 }
   1243 
   1244 
   1245 function ProtocolMessage(request) {
   1246   // Update sequence number.
   1247   this.seq = next_response_seq++;
   1248 
   1249   if (request) {
   1250     // If message is based on a request this is a response. Fill the initial
   1251     // response from the request.
   1252     this.type = 'response';
   1253     this.request_seq = request.seq;
   1254     this.command = request.command;
   1255   } else {
   1256     // If message is not based on a request it is a dabugger generated event.
   1257     this.type = 'event';
   1258   }
   1259   this.success = true;
   1260   // Handler may set this field to control debugger state.
   1261   this.running = undefined;
   1262 }
   1263 
   1264 
   1265 ProtocolMessage.prototype.setOption = function(name, value) {
   1266   if (!this.options_) {
   1267     this.options_ = {};
   1268   }
   1269   this.options_[name] = value;
   1270 }
   1271 
   1272 
   1273 ProtocolMessage.prototype.failed = function(message) {
   1274   this.success = false;
   1275   this.message = message;
   1276 }
   1277 
   1278 
   1279 ProtocolMessage.prototype.toJSONProtocol = function() {
   1280   // Encode the protocol header.
   1281   var json = {};
   1282   json.seq= this.seq;
   1283   if (this.request_seq) {
   1284     json.request_seq = this.request_seq;
   1285   }
   1286   json.type = this.type;
   1287   if (this.event) {
   1288     json.event = this.event;
   1289   }
   1290   if (this.command) {
   1291     json.command = this.command;
   1292   }
   1293   if (this.success) {
   1294     json.success = this.success;
   1295   } else {
   1296     json.success = false;
   1297   }
   1298   if (this.body) {
   1299     // Encode the body part.
   1300     var bodyJson;
   1301     var serializer = MakeMirrorSerializer(true, this.options_);
   1302     if (this.body instanceof Mirror) {
   1303       bodyJson = serializer.serializeValue(this.body);
   1304     } else if (this.body instanceof Array) {
   1305       bodyJson = [];
   1306       for (var i = 0; i < this.body.length; i++) {
   1307         if (this.body[i] instanceof Mirror) {
   1308           bodyJson.push(serializer.serializeValue(this.body[i]));
   1309         } else {
   1310           bodyJson.push(ObjectToProtocolObject_(this.body[i], serializer));
   1311         }
   1312       }
   1313     } else {
   1314       bodyJson = ObjectToProtocolObject_(this.body, serializer);
   1315     }
   1316     json.body = bodyJson;
   1317     json.refs = serializer.serializeReferencedObjects();
   1318   }
   1319   if (this.message) {
   1320     json.message = this.message;
   1321   }
   1322   json.running = this.running;
   1323   return JSON.stringify(json);
   1324 }
   1325 
   1326 
   1327 DebugCommandProcessor.prototype.createResponse = function(request) {
   1328   return new ProtocolMessage(request);
   1329 };
   1330 
   1331 
   1332 DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) {
   1333   var request;  // Current request.
   1334   var response;  // Generated response.
   1335   try {
   1336     try {
   1337       // Convert the JSON string to an object.
   1338       request = %CompileString('(' + json_request + ')')();
   1339 
   1340       // Create an initial response.
   1341       response = this.createResponse(request);
   1342 
   1343       if (!request.type) {
   1344         throw new Error('Type not specified');
   1345       }
   1346 
   1347       if (request.type != 'request') {
   1348         throw new Error("Illegal type '" + request.type + "' in request");
   1349       }
   1350 
   1351       if (!request.command) {
   1352         throw new Error('Command not specified');
   1353       }
   1354 
   1355       if (request.arguments) {
   1356         var args = request.arguments;
   1357         // TODO(yurys): remove request.arguments.compactFormat check once
   1358         // ChromeDevTools are switched to 'inlineRefs'
   1359         if (args.inlineRefs || args.compactFormat) {
   1360           response.setOption('inlineRefs', true);
   1361         }
   1362         if (!IS_UNDEFINED(args.maxStringLength)) {
   1363           response.setOption('maxStringLength', args.maxStringLength);
   1364         }
   1365       }
   1366 
   1367       if (request.command == 'continue') {
   1368         this.continueRequest_(request, response);
   1369       } else if (request.command == 'break') {
   1370         this.breakRequest_(request, response);
   1371       } else if (request.command == 'setbreakpoint') {
   1372         this.setBreakPointRequest_(request, response);
   1373       } else if (request.command == 'changebreakpoint') {
   1374         this.changeBreakPointRequest_(request, response);
   1375       } else if (request.command == 'clearbreakpoint') {
   1376         this.clearBreakPointRequest_(request, response);
   1377       } else if (request.command == 'clearbreakpointgroup') {
   1378         this.clearBreakPointGroupRequest_(request, response);
   1379       } else if (request.command == 'disconnect') {
   1380         this.disconnectRequest_(request, response);
   1381       } else if (request.command == 'setexceptionbreak') {
   1382         this.setExceptionBreakRequest_(request, response);
   1383       } else if (request.command == 'listbreakpoints') {
   1384         this.listBreakpointsRequest_(request, response);
   1385       } else if (request.command == 'backtrace') {
   1386         this.backtraceRequest_(request, response);
   1387       } else if (request.command == 'frame') {
   1388         this.frameRequest_(request, response);
   1389       } else if (request.command == 'scopes') {
   1390         this.scopesRequest_(request, response);
   1391       } else if (request.command == 'scope') {
   1392         this.scopeRequest_(request, response);
   1393       } else if (request.command == 'evaluate') {
   1394         this.evaluateRequest_(request, response);
   1395       } else if (lol_is_enabled && request.command == 'getobj') {
   1396         this.getobjRequest_(request, response);
   1397       } else if (request.command == 'lookup') {
   1398         this.lookupRequest_(request, response);
   1399       } else if (request.command == 'references') {
   1400         this.referencesRequest_(request, response);
   1401       } else if (request.command == 'source') {
   1402         this.sourceRequest_(request, response);
   1403       } else if (request.command == 'scripts') {
   1404         this.scriptsRequest_(request, response);
   1405       } else if (request.command == 'threads') {
   1406         this.threadsRequest_(request, response);
   1407       } else if (request.command == 'suspend') {
   1408         this.suspendRequest_(request, response);
   1409       } else if (request.command == 'version') {
   1410         this.versionRequest_(request, response);
   1411       } else if (request.command == 'profile') {
   1412         this.profileRequest_(request, response);
   1413       } else if (request.command == 'changelive') {
   1414         this.changeLiveRequest_(request, response);
   1415       } else if (request.command == 'flags') {
   1416         this.debuggerFlagsRequest_(request, response);
   1417       } else if (request.command == 'v8flags') {
   1418         this.v8FlagsRequest_(request, response);
   1419 
   1420       // GC tools:
   1421       } else if (request.command == 'gc') {
   1422         this.gcRequest_(request, response);
   1423 
   1424       // LiveObjectList tools:
   1425       } else if (lol_is_enabled && request.command == 'lol-capture') {
   1426         this.lolCaptureRequest_(request, response);
   1427       } else if (lol_is_enabled && request.command == 'lol-delete') {
   1428         this.lolDeleteRequest_(request, response);
   1429       } else if (lol_is_enabled && request.command == 'lol-diff') {
   1430         this.lolDiffRequest_(request, response);
   1431       } else if (lol_is_enabled && request.command == 'lol-getid') {
   1432         this.lolGetIdRequest_(request, response);
   1433       } else if (lol_is_enabled && request.command == 'lol-info') {
   1434         this.lolInfoRequest_(request, response);
   1435       } else if (lol_is_enabled && request.command == 'lol-reset') {
   1436         this.lolResetRequest_(request, response);
   1437       } else if (lol_is_enabled && request.command == 'lol-retainers') {
   1438         this.lolRetainersRequest_(request, response);
   1439       } else if (lol_is_enabled && request.command == 'lol-path') {
   1440         this.lolPathRequest_(request, response);
   1441       } else if (lol_is_enabled && request.command == 'lol-print') {
   1442         this.lolPrintRequest_(request, response);
   1443       } else if (lol_is_enabled && request.command == 'lol-stats') {
   1444         this.lolStatsRequest_(request, response);
   1445 
   1446       } else {
   1447         throw new Error('Unknown command "' + request.command + '" in request');
   1448       }
   1449     } catch (e) {
   1450       // If there is no response object created one (without command).
   1451       if (!response) {
   1452         response = this.createResponse();
   1453       }
   1454       response.success = false;
   1455       response.message = %ToString(e);
   1456     }
   1457 
   1458     // Return the response as a JSON encoded string.
   1459     try {
   1460       if (!IS_UNDEFINED(response.running)) {
   1461         // Response controls running state.
   1462         this.running_ = response.running;
   1463       }
   1464       response.running = this.running_;
   1465       return response.toJSONProtocol();
   1466     } catch (e) {
   1467       // Failed to generate response - return generic error.
   1468       return '{"seq":' + response.seq + ',' +
   1469               '"request_seq":' + request.seq + ',' +
   1470               '"type":"response",' +
   1471               '"success":false,' +
   1472               '"message":"Internal error: ' + %ToString(e) + '"}';
   1473     }
   1474   } catch (e) {
   1475     // Failed in one of the catch blocks above - most generic error.
   1476     return '{"seq":0,"type":"response","success":false,"message":"Internal error"}';
   1477   }
   1478 };
   1479 
   1480 
   1481 DebugCommandProcessor.prototype.continueRequest_ = function(request, response) {
   1482   // Check for arguments for continue.
   1483   if (request.arguments) {
   1484     var count = 1;
   1485     var action = Debug.StepAction.StepIn;
   1486 
   1487     // Pull out arguments.
   1488     var stepaction = request.arguments.stepaction;
   1489     var stepcount = request.arguments.stepcount;
   1490 
   1491     // Get the stepcount argument if any.
   1492     if (stepcount) {
   1493       count = %ToNumber(stepcount);
   1494       if (count < 0) {
   1495         throw new Error('Invalid stepcount argument "' + stepcount + '".');
   1496       }
   1497     }
   1498 
   1499     // Get the stepaction argument.
   1500     if (stepaction) {
   1501       if (stepaction == 'in') {
   1502         action = Debug.StepAction.StepIn;
   1503       } else if (stepaction == 'min') {
   1504         action = Debug.StepAction.StepMin;
   1505       } else if (stepaction == 'next') {
   1506         action = Debug.StepAction.StepNext;
   1507       } else if (stepaction == 'out') {
   1508         action = Debug.StepAction.StepOut;
   1509       } else {
   1510         throw new Error('Invalid stepaction argument "' + stepaction + '".');
   1511       }
   1512     }
   1513 
   1514     // Setup the VM for stepping.
   1515     this.exec_state_.prepareStep(action, count);
   1516   }
   1517 
   1518   // VM should be running after executing this request.
   1519   response.running = true;
   1520 };
   1521 
   1522 
   1523 DebugCommandProcessor.prototype.breakRequest_ = function(request, response) {
   1524   // Ignore as break command does not do anything when broken.
   1525 };
   1526 
   1527 
   1528 DebugCommandProcessor.prototype.setBreakPointRequest_ =
   1529     function(request, response) {
   1530   // Check for legal request.
   1531   if (!request.arguments) {
   1532     response.failed('Missing arguments');
   1533     return;
   1534   }
   1535 
   1536   // Pull out arguments.
   1537   var type = request.arguments.type;
   1538   var target = request.arguments.target;
   1539   var line = request.arguments.line;
   1540   var column = request.arguments.column;
   1541   var enabled = IS_UNDEFINED(request.arguments.enabled) ?
   1542       true : request.arguments.enabled;
   1543   var condition = request.arguments.condition;
   1544   var ignoreCount = request.arguments.ignoreCount;
   1545   var groupId = request.arguments.groupId;
   1546 
   1547   // Check for legal arguments.
   1548   if (!type || IS_UNDEFINED(target)) {
   1549     response.failed('Missing argument "type" or "target"');
   1550     return;
   1551   }
   1552   if (type != 'function' && type != 'handle' &&
   1553       type != 'script' && type != 'scriptId') {
   1554     response.failed('Illegal type "' + type + '"');
   1555     return;
   1556   }
   1557 
   1558   // Either function or script break point.
   1559   var break_point_number;
   1560   if (type == 'function') {
   1561     // Handle function break point.
   1562     if (!IS_STRING(target)) {
   1563       response.failed('Argument "target" is not a string value');
   1564       return;
   1565     }
   1566     var f;
   1567     try {
   1568       // Find the function through a global evaluate.
   1569       f = this.exec_state_.evaluateGlobal(target).value();
   1570     } catch (e) {
   1571       response.failed('Error: "' + %ToString(e) +
   1572                       '" evaluating "' + target + '"');
   1573       return;
   1574     }
   1575     if (!IS_FUNCTION(f)) {
   1576       response.failed('"' + target + '" does not evaluate to a function');
   1577       return;
   1578     }
   1579 
   1580     // Set function break point.
   1581     break_point_number = Debug.setBreakPoint(f, line, column, condition);
   1582   } else if (type == 'handle') {
   1583     // Find the object pointed by the specified handle.
   1584     var handle = parseInt(target, 10);
   1585     var mirror = LookupMirror(handle);
   1586     if (!mirror) {
   1587       return response.failed('Object #' + handle + '# not found');
   1588     }
   1589     if (!mirror.isFunction()) {
   1590       return response.failed('Object #' + handle + '# is not a function');
   1591     }
   1592 
   1593     // Set function break point.
   1594     break_point_number = Debug.setBreakPoint(mirror.value(),
   1595                                              line, column, condition);
   1596   } else if (type == 'script') {
   1597     // set script break point.
   1598     break_point_number =
   1599         Debug.setScriptBreakPointByName(target, line, column, condition,
   1600                                         groupId);
   1601   } else {  // type == 'scriptId.
   1602     break_point_number =
   1603         Debug.setScriptBreakPointById(target, line, column, condition, groupId);
   1604   }
   1605 
   1606   // Set additional break point properties.
   1607   var break_point = Debug.findBreakPoint(break_point_number);
   1608   if (ignoreCount) {
   1609     Debug.changeBreakPointIgnoreCount(break_point_number, ignoreCount);
   1610   }
   1611   if (!enabled) {
   1612     Debug.disableBreakPoint(break_point_number);
   1613   }
   1614 
   1615   // Add the break point number to the response.
   1616   response.body = { type: type,
   1617                     breakpoint: break_point_number }
   1618 
   1619   // Add break point information to the response.
   1620   if (break_point instanceof ScriptBreakPoint) {
   1621     if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
   1622       response.body.type = 'scriptId';
   1623       response.body.script_id = break_point.script_id();
   1624     } else {
   1625       response.body.type = 'scriptName';
   1626       response.body.script_name = break_point.script_name();
   1627     }
   1628     response.body.line = break_point.line();
   1629     response.body.column = break_point.column();
   1630     response.body.actual_locations = break_point.actual_locations();
   1631   } else {
   1632     response.body.type = 'function';
   1633     response.body.actual_locations = [break_point.actual_location];
   1634   }
   1635 };
   1636 
   1637 
   1638 DebugCommandProcessor.prototype.changeBreakPointRequest_ = function(request, response) {
   1639   // Check for legal request.
   1640   if (!request.arguments) {
   1641     response.failed('Missing arguments');
   1642     return;
   1643   }
   1644 
   1645   // Pull out arguments.
   1646   var break_point = %ToNumber(request.arguments.breakpoint);
   1647   var enabled = request.arguments.enabled;
   1648   var condition = request.arguments.condition;
   1649   var ignoreCount = request.arguments.ignoreCount;
   1650 
   1651   // Check for legal arguments.
   1652   if (!break_point) {
   1653     response.failed('Missing argument "breakpoint"');
   1654     return;
   1655   }
   1656 
   1657   // Change enabled state if supplied.
   1658   if (!IS_UNDEFINED(enabled)) {
   1659     if (enabled) {
   1660       Debug.enableBreakPoint(break_point);
   1661     } else {
   1662       Debug.disableBreakPoint(break_point);
   1663     }
   1664   }
   1665 
   1666   // Change condition if supplied
   1667   if (!IS_UNDEFINED(condition)) {
   1668     Debug.changeBreakPointCondition(break_point, condition);
   1669   }
   1670 
   1671   // Change ignore count if supplied
   1672   if (!IS_UNDEFINED(ignoreCount)) {
   1673     Debug.changeBreakPointIgnoreCount(break_point, ignoreCount);
   1674   }
   1675 }
   1676 
   1677 
   1678 DebugCommandProcessor.prototype.clearBreakPointGroupRequest_ = function(request, response) {
   1679   // Check for legal request.
   1680   if (!request.arguments) {
   1681     response.failed('Missing arguments');
   1682     return;
   1683   }
   1684 
   1685   // Pull out arguments.
   1686   var group_id = request.arguments.groupId;
   1687 
   1688   // Check for legal arguments.
   1689   if (!group_id) {
   1690     response.failed('Missing argument "groupId"');
   1691     return;
   1692   }
   1693 
   1694   var cleared_break_points = [];
   1695   var new_script_break_points = [];
   1696   for (var i = 0; i < script_break_points.length; i++) {
   1697     var next_break_point = script_break_points[i];
   1698     if (next_break_point.groupId() == group_id) {
   1699       cleared_break_points.push(next_break_point.number());
   1700       next_break_point.clear();
   1701     } else {
   1702       new_script_break_points.push(next_break_point);
   1703     }
   1704   }
   1705   script_break_points = new_script_break_points;
   1706 
   1707   // Add the cleared break point numbers to the response.
   1708   response.body = { breakpoints: cleared_break_points };
   1709 }
   1710 
   1711 
   1712 DebugCommandProcessor.prototype.clearBreakPointRequest_ = function(request, response) {
   1713   // Check for legal request.
   1714   if (!request.arguments) {
   1715     response.failed('Missing arguments');
   1716     return;
   1717   }
   1718 
   1719   // Pull out arguments.
   1720   var break_point = %ToNumber(request.arguments.breakpoint);
   1721 
   1722   // Check for legal arguments.
   1723   if (!break_point) {
   1724     response.failed('Missing argument "breakpoint"');
   1725     return;
   1726   }
   1727 
   1728   // Clear break point.
   1729   Debug.clearBreakPoint(break_point);
   1730 
   1731   // Add the cleared break point number to the response.
   1732   response.body = { breakpoint: break_point }
   1733 }
   1734 
   1735 
   1736 DebugCommandProcessor.prototype.listBreakpointsRequest_ = function(request, response) {
   1737   var array = [];
   1738   for (var i = 0; i < script_break_points.length; i++) {
   1739     var break_point = script_break_points[i];
   1740 
   1741     var description = {
   1742       number: break_point.number(),
   1743       line: break_point.line(),
   1744       column: break_point.column(),
   1745       groupId: break_point.groupId(),
   1746       hit_count: break_point.hit_count(),
   1747       active: break_point.active(),
   1748       condition: break_point.condition(),
   1749       ignoreCount: break_point.ignoreCount(),
   1750       actual_locations: break_point.actual_locations()
   1751     }
   1752 
   1753     if (break_point.type() == Debug.ScriptBreakPointType.ScriptId) {
   1754       description.type = 'scriptId';
   1755       description.script_id = break_point.script_id();
   1756     } else {
   1757       description.type = 'scriptName';
   1758       description.script_name = break_point.script_name();
   1759     }
   1760     array.push(description);
   1761   }
   1762 
   1763   response.body = {
   1764     breakpoints: array,
   1765     breakOnExceptions: Debug.isBreakOnException(),
   1766     breakOnUncaughtExceptions: Debug.isBreakOnUncaughtException()
   1767   }
   1768 }
   1769 
   1770 
   1771 DebugCommandProcessor.prototype.disconnectRequest_ =
   1772     function(request, response) {
   1773   Debug.disableAllBreakPoints();
   1774   this.continueRequest_(request, response);
   1775 }
   1776 
   1777 
   1778 DebugCommandProcessor.prototype.setExceptionBreakRequest_ =
   1779     function(request, response) {
   1780   // Check for legal request.
   1781   if (!request.arguments) {
   1782     response.failed('Missing arguments');
   1783     return;
   1784   }
   1785 
   1786   // Pull out and check the 'type' argument:
   1787   var type = request.arguments.type;
   1788   if (!type) {
   1789     response.failed('Missing argument "type"');
   1790     return;
   1791   }
   1792 
   1793   // Initialize the default value of enable:
   1794   var enabled;
   1795   if (type == 'all') {
   1796     enabled = !Debug.isBreakOnException();
   1797   } else if (type == 'uncaught') {
   1798     enabled = !Debug.isBreakOnUncaughtException();
   1799   }  
   1800 
   1801   // Pull out and check the 'enabled' argument if present:
   1802   if (!IS_UNDEFINED(request.arguments.enabled)) {
   1803     enabled = request.arguments.enabled;
   1804     if ((enabled != true) && (enabled != false)) {
   1805       response.failed('Illegal value for "enabled":"' + enabled + '"');
   1806     }
   1807   }
   1808 
   1809   // Now set the exception break state:
   1810   if (type == 'all') {
   1811     %ChangeBreakOnException(Debug.ExceptionBreak.Caught, enabled);
   1812   } else if (type == 'uncaught') {
   1813     %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, enabled);
   1814   } else {
   1815     response.failed('Unknown "type":"' + type + '"');
   1816   }
   1817 
   1818   // Add the cleared break point number to the response.
   1819   response.body = { 'type': type, 'enabled': enabled };
   1820 }
   1821 
   1822 
   1823 DebugCommandProcessor.prototype.backtraceRequest_ = function(request, response) {
   1824   // Get the number of frames.
   1825   var total_frames = this.exec_state_.frameCount();
   1826 
   1827   // Create simple response if there are no frames.
   1828   if (total_frames == 0) {
   1829     response.body = {
   1830       totalFrames: total_frames
   1831     }
   1832     return;
   1833   }
   1834 
   1835   // Default frame range to include in backtrace.
   1836   var from_index = 0
   1837   var to_index = kDefaultBacktraceLength;
   1838 
   1839   // Get the range from the arguments.
   1840   if (request.arguments) {
   1841     if (request.arguments.fromFrame) {
   1842       from_index = request.arguments.fromFrame;
   1843     }
   1844     if (request.arguments.toFrame) {
   1845       to_index = request.arguments.toFrame;
   1846     }
   1847     if (request.arguments.bottom) {
   1848       var tmp_index = total_frames - from_index;
   1849       from_index = total_frames - to_index
   1850       to_index = tmp_index;
   1851     }
   1852     if (from_index < 0 || to_index < 0) {
   1853       return response.failed('Invalid frame number');
   1854     }
   1855   }
   1856 
   1857   // Adjust the index.
   1858   to_index = Math.min(total_frames, to_index);
   1859 
   1860   if (to_index <= from_index) {
   1861     var error = 'Invalid frame range';
   1862     return response.failed(error);
   1863   }
   1864 
   1865   // Create the response body.
   1866   var frames = [];
   1867   for (var i = from_index; i < to_index; i++) {
   1868     frames.push(this.exec_state_.frame(i));
   1869   }
   1870   response.body = {
   1871     fromFrame: from_index,
   1872     toFrame: to_index,
   1873     totalFrames: total_frames,
   1874     frames: frames
   1875   }
   1876 };
   1877 
   1878 
   1879 DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
   1880   // No frames no source.
   1881   if (this.exec_state_.frameCount() == 0) {
   1882     return response.failed('No frames');
   1883   }
   1884 
   1885   // With no arguments just keep the selected frame.
   1886   if (request.arguments) {
   1887     var index = request.arguments.number;
   1888     if (index < 0 || this.exec_state_.frameCount() <= index) {
   1889       return response.failed('Invalid frame number');
   1890     }
   1891 
   1892     this.exec_state_.setSelectedFrame(request.arguments.number);
   1893   }
   1894   response.body = this.exec_state_.frame();
   1895 };
   1896 
   1897 
   1898 DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
   1899   // Get the frame for which the scope or scopes are requested. With no frameNumber
   1900   // argument use the currently selected frame.
   1901   if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
   1902     frame_index = request.arguments.frameNumber;
   1903     if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
   1904       return response.failed('Invalid frame number');
   1905     }
   1906     return this.exec_state_.frame(frame_index);
   1907   } else {
   1908     return this.exec_state_.frame();
   1909   }
   1910 }
   1911 
   1912 
   1913 DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
   1914   // No frames no scopes.
   1915   if (this.exec_state_.frameCount() == 0) {
   1916     return response.failed('No scopes');
   1917   }
   1918 
   1919   // Get the frame for which the scopes are requested.
   1920   var frame = this.frameForScopeRequest_(request);
   1921 
   1922   // Fill all scopes for this frame.
   1923   var total_scopes = frame.scopeCount();
   1924   var scopes = [];
   1925   for (var i = 0; i < total_scopes; i++) {
   1926     scopes.push(frame.scope(i));
   1927   }
   1928   response.body = {
   1929     fromScope: 0,
   1930     toScope: total_scopes,
   1931     totalScopes: total_scopes,
   1932     scopes: scopes
   1933   }
   1934 };
   1935 
   1936 
   1937 DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
   1938   // No frames no scopes.
   1939   if (this.exec_state_.frameCount() == 0) {
   1940     return response.failed('No scopes');
   1941   }
   1942 
   1943   // Get the frame for which the scope is requested.
   1944   var frame = this.frameForScopeRequest_(request);
   1945 
   1946   // With no scope argument just return top scope.
   1947   var scope_index = 0;
   1948   if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
   1949     scope_index = %ToNumber(request.arguments.number);
   1950     if (scope_index < 0 || frame.scopeCount() <= scope_index) {
   1951       return response.failed('Invalid scope number');
   1952     }
   1953   }
   1954 
   1955   response.body = frame.scope(scope_index);
   1956 };
   1957 
   1958 
   1959 DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
   1960   if (!request.arguments) {
   1961     return response.failed('Missing arguments');
   1962   }
   1963 
   1964   // Pull out arguments.
   1965   var expression = request.arguments.expression;
   1966   var frame = request.arguments.frame;
   1967   var global = request.arguments.global;
   1968   var disable_break = request.arguments.disable_break;
   1969   var additional_context = request.arguments.additional_context;
   1970 
   1971   // The expression argument could be an integer so we convert it to a
   1972   // string.
   1973   try {
   1974     expression = String(expression);
   1975   } catch(e) {
   1976     return response.failed('Failed to convert expression argument to string');
   1977   }
   1978 
   1979   // Check for legal arguments.
   1980   if (!IS_UNDEFINED(frame) && global) {
   1981     return response.failed('Arguments "frame" and "global" are exclusive');
   1982   }
   1983   
   1984   var additional_context_object;
   1985   if (additional_context) {
   1986     additional_context_object = {};
   1987     for (var i = 0; i < additional_context.length; i++) {
   1988       var mapping = additional_context[i];
   1989       if (!IS_STRING(mapping.name) || !IS_NUMBER(mapping.handle)) {
   1990         return response.failed("Context element #" + i + 
   1991             " must contain name:string and handle:number");
   1992       } 
   1993       var context_value_mirror = LookupMirror(mapping.handle);
   1994       if (!context_value_mirror) {
   1995         return response.failed("Context object '" + mapping.name +
   1996             "' #" + mapping.handle + "# not found");
   1997       }
   1998       additional_context_object[mapping.name] = context_value_mirror.value(); 
   1999     }
   2000   }
   2001 
   2002   // Global evaluate.
   2003   if (global) {
   2004     // Evaluate in the global context.
   2005     response.body = this.exec_state_.evaluateGlobal(
   2006         expression, Boolean(disable_break), additional_context_object);
   2007     return;
   2008   }
   2009 
   2010   // Default value for disable_break is true.
   2011   if (IS_UNDEFINED(disable_break)) {
   2012     disable_break = true;
   2013   }
   2014 
   2015   // No frames no evaluate in frame.
   2016   if (this.exec_state_.frameCount() == 0) {
   2017     return response.failed('No frames');
   2018   }
   2019 
   2020   // Check whether a frame was specified.
   2021   if (!IS_UNDEFINED(frame)) {
   2022     var frame_number = %ToNumber(frame);
   2023     if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
   2024       return response.failed('Invalid frame "' + frame + '"');
   2025     }
   2026     // Evaluate in the specified frame.
   2027     response.body = this.exec_state_.frame(frame_number).evaluate(
   2028         expression, Boolean(disable_break), additional_context_object);
   2029     return;
   2030   } else {
   2031     // Evaluate in the selected frame.
   2032     response.body = this.exec_state_.frame().evaluate(
   2033         expression, Boolean(disable_break), additional_context_object);
   2034     return;
   2035   }
   2036 };
   2037 
   2038 
   2039 DebugCommandProcessor.prototype.getobjRequest_ = function(request, response) {
   2040   if (!request.arguments) {
   2041     return response.failed('Missing arguments');
   2042   }
   2043 
   2044   // Pull out arguments.
   2045   var obj_id = request.arguments.obj_id;
   2046 
   2047   // Check for legal arguments.
   2048   if (IS_UNDEFINED(obj_id)) {
   2049     return response.failed('Argument "obj_id" missing');
   2050   }
   2051 
   2052   // Dump the object.
   2053   response.body = MakeMirror(%GetLOLObj(obj_id));
   2054 };
   2055 
   2056 
   2057 DebugCommandProcessor.prototype.lookupRequest_ = function(request, response) {
   2058   if (!request.arguments) {
   2059     return response.failed('Missing arguments');
   2060   }
   2061 
   2062   // Pull out arguments.
   2063   var handles = request.arguments.handles;
   2064 
   2065   // Check for legal arguments.
   2066   if (IS_UNDEFINED(handles)) {
   2067     return response.failed('Argument "handles" missing');
   2068   }
   2069 
   2070   // Set 'includeSource' option for script lookup.
   2071   if (!IS_UNDEFINED(request.arguments.includeSource)) {
   2072     includeSource = %ToBoolean(request.arguments.includeSource);
   2073     response.setOption('includeSource', includeSource);
   2074   }
   2075 
   2076   // Lookup handles.
   2077   var mirrors = {};
   2078   for (var i = 0; i < handles.length; i++) {
   2079     var handle = handles[i];
   2080     var mirror = LookupMirror(handle);
   2081     if (!mirror) {
   2082       return response.failed('Object #' + handle + '# not found');
   2083     }
   2084     mirrors[handle] = mirror;
   2085   }
   2086   response.body = mirrors;
   2087 };
   2088 
   2089 
   2090 DebugCommandProcessor.prototype.referencesRequest_ =
   2091     function(request, response) {
   2092   if (!request.arguments) {
   2093     return response.failed('Missing arguments');
   2094   }
   2095 
   2096   // Pull out arguments.
   2097   var type = request.arguments.type;
   2098   var handle = request.arguments.handle;
   2099 
   2100   // Check for legal arguments.
   2101   if (IS_UNDEFINED(type)) {
   2102     return response.failed('Argument "type" missing');
   2103   }
   2104   if (IS_UNDEFINED(handle)) {
   2105     return response.failed('Argument "handle" missing');
   2106   }
   2107   if (type != 'referencedBy' && type != 'constructedBy') {
   2108     return response.failed('Invalid type "' + type + '"');
   2109   }
   2110 
   2111   // Lookup handle and return objects with references the object.
   2112   var mirror = LookupMirror(handle);
   2113   if (mirror) {
   2114     if (type == 'referencedBy') {
   2115       response.body = mirror.referencedBy();
   2116     } else {
   2117       response.body = mirror.constructedBy();
   2118     }
   2119   } else {
   2120     return response.failed('Object #' + handle + '# not found');
   2121   }
   2122 };
   2123 
   2124 
   2125 DebugCommandProcessor.prototype.sourceRequest_ = function(request, response) {
   2126   // No frames no source.
   2127   if (this.exec_state_.frameCount() == 0) {
   2128     return response.failed('No source');
   2129   }
   2130 
   2131   var from_line;
   2132   var to_line;
   2133   var frame = this.exec_state_.frame();
   2134   if (request.arguments) {
   2135     // Pull out arguments.
   2136     from_line = request.arguments.fromLine;
   2137     to_line = request.arguments.toLine;
   2138 
   2139     if (!IS_UNDEFINED(request.arguments.frame)) {
   2140       var frame_number = %ToNumber(request.arguments.frame);
   2141       if (frame_number < 0 || frame_number >= this.exec_state_.frameCount()) {
   2142         return response.failed('Invalid frame "' + frame + '"');
   2143       }
   2144       frame = this.exec_state_.frame(frame_number);
   2145     }
   2146   }
   2147 
   2148   // Get the script selected.
   2149   var script = frame.func().script();
   2150   if (!script) {
   2151     return response.failed('No source');
   2152   }
   2153 
   2154   // Get the source slice and fill it into the response.
   2155   var slice = script.sourceSlice(from_line, to_line);
   2156   if (!slice) {
   2157     return response.failed('Invalid line interval');
   2158   }
   2159   response.body = {};
   2160   response.body.source = slice.sourceText();
   2161   response.body.fromLine = slice.from_line;
   2162   response.body.toLine = slice.to_line;
   2163   response.body.fromPosition = slice.from_position;
   2164   response.body.toPosition = slice.to_position;
   2165   response.body.totalLines = script.lineCount();
   2166 };
   2167 
   2168 
   2169 DebugCommandProcessor.prototype.scriptsRequest_ = function(request, response) {
   2170   var types = ScriptTypeFlag(Debug.ScriptType.Normal);
   2171   var includeSource = false;
   2172   var idsToInclude = null;
   2173   if (request.arguments) {
   2174     // Pull out arguments.
   2175     if (!IS_UNDEFINED(request.arguments.types)) {
   2176       types = %ToNumber(request.arguments.types);
   2177       if (isNaN(types) || types < 0) {
   2178         return response.failed('Invalid types "' + request.arguments.types + '"');
   2179       }
   2180     }
   2181 
   2182     if (!IS_UNDEFINED(request.arguments.includeSource)) {
   2183       includeSource = %ToBoolean(request.arguments.includeSource);
   2184       response.setOption('includeSource', includeSource);
   2185     }
   2186 
   2187     if (IS_ARRAY(request.arguments.ids)) {
   2188       idsToInclude = {};
   2189       var ids = request.arguments.ids;
   2190       for (var i = 0; i < ids.length; i++) {
   2191         idsToInclude[ids[i]] = true;
   2192       }
   2193     }
   2194 
   2195     var filterStr = null;
   2196     var filterNum = null;
   2197     if (!IS_UNDEFINED(request.arguments.filter)) {
   2198       var num = %ToNumber(request.arguments.filter);
   2199       if (!isNaN(num)) {
   2200         filterNum = num;
   2201       }
   2202       filterStr = request.arguments.filter;
   2203     }
   2204   }
   2205 
   2206   // Collect all scripts in the heap.
   2207   var scripts = %DebugGetLoadedScripts();
   2208 
   2209   response.body = [];
   2210 
   2211   for (var i = 0; i < scripts.length; i++) {
   2212     if (idsToInclude && !idsToInclude[scripts[i].id]) {
   2213       continue;
   2214     }
   2215     if (filterStr || filterNum) {
   2216       var script = scripts[i];
   2217       var found = false;
   2218       if (filterNum && !found) {
   2219         if (script.id && script.id === filterNum) {
   2220           found = true;
   2221         }
   2222       }
   2223       if (filterStr && !found) {
   2224         if (script.name && script.name.indexOf(filterStr) >= 0) {
   2225           found = true;
   2226         }
   2227       }
   2228       if (!found) continue;
   2229     }
   2230     if (types & ScriptTypeFlag(scripts[i].type)) {
   2231       response.body.push(MakeMirror(scripts[i]));
   2232     }
   2233   }
   2234 };
   2235 
   2236 
   2237 DebugCommandProcessor.prototype.threadsRequest_ = function(request, response) {
   2238   // Get the number of threads.
   2239   var total_threads = this.exec_state_.threadCount();
   2240 
   2241   // Get information for all threads.
   2242   var threads = [];
   2243   for (var i = 0; i < total_threads; i++) {
   2244     var details = %GetThreadDetails(this.exec_state_.break_id, i);
   2245     var thread_info = { current: details[0],
   2246                         id: details[1]
   2247                       }
   2248     threads.push(thread_info);
   2249   }
   2250 
   2251   // Create the response body.
   2252   response.body = {
   2253     totalThreads: total_threads,
   2254     threads: threads
   2255   }
   2256 };
   2257 
   2258 
   2259 DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
   2260   response.running = false;
   2261 };
   2262 
   2263 
   2264 DebugCommandProcessor.prototype.versionRequest_ = function(request, response) {
   2265   response.body = {
   2266     V8Version: %GetV8Version()
   2267   }
   2268 };
   2269 
   2270 
   2271 DebugCommandProcessor.prototype.profileRequest_ = function(request, response) {
   2272   if (!request.arguments) {
   2273     return response.failed('Missing arguments');
   2274   }
   2275   var modules = parseInt(request.arguments.modules);
   2276   if (isNaN(modules)) {
   2277     return response.failed('Modules is not an integer');
   2278   }
   2279   var tag = parseInt(request.arguments.tag);
   2280   if (isNaN(tag)) {
   2281     tag = 0;
   2282   }
   2283   if (request.arguments.command == 'resume') {
   2284     %ProfilerResume(modules, tag);
   2285   } else if (request.arguments.command == 'pause') {
   2286     %ProfilerPause(modules, tag);
   2287   } else {
   2288     return response.failed('Unknown command');
   2289   }
   2290   response.body = {};
   2291 };
   2292 
   2293 
   2294 DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) {
   2295   if (!Debug.LiveEdit) {
   2296     return response.failed('LiveEdit feature is not supported');
   2297   }
   2298   if (!request.arguments) {
   2299     return response.failed('Missing arguments');
   2300   }
   2301   var script_id = request.arguments.script_id;
   2302   var preview_only = !!request.arguments.preview_only;
   2303 
   2304   var scripts = %DebugGetLoadedScripts();
   2305 
   2306   var the_script = null;
   2307   for (var i = 0; i < scripts.length; i++) {
   2308     if (scripts[i].id == script_id) {
   2309       the_script = scripts[i];
   2310     }
   2311   }
   2312   if (!the_script) {
   2313     response.failed('Script not found');
   2314     return;
   2315   }
   2316 
   2317   var change_log = new Array();
   2318 
   2319   if (!IS_STRING(request.arguments.new_source)) {
   2320     throw "new_source argument expected";
   2321   }
   2322 
   2323   var new_source = request.arguments.new_source;
   2324 
   2325   var result_description = Debug.LiveEdit.SetScriptSource(the_script,
   2326       new_source, preview_only, change_log);
   2327   response.body = {change_log: change_log, result: result_description};
   2328 
   2329   if (!preview_only && !this.running_ && result_description.stack_modified) {
   2330     response.body.stepin_recommended = true;
   2331   }
   2332 };
   2333 
   2334 
   2335 DebugCommandProcessor.prototype.debuggerFlagsRequest_ = function(request,
   2336                                                                  response) {
   2337   // Check for legal request.
   2338   if (!request.arguments) {
   2339     response.failed('Missing arguments');
   2340     return;
   2341   }
   2342 
   2343   // Pull out arguments.
   2344   var flags = request.arguments.flags;
   2345 
   2346   response.body = { flags: [] };
   2347   if (!IS_UNDEFINED(flags)) {
   2348     for (var i = 0; i < flags.length; i++) {
   2349       var name = flags[i].name;
   2350       var debugger_flag = debugger_flags[name];
   2351       if (!debugger_flag) {
   2352         continue;
   2353       }
   2354       if ('value' in flags[i]) {
   2355         debugger_flag.setValue(flags[i].value);
   2356       }
   2357       response.body.flags.push({ name: name, value: debugger_flag.getValue() });
   2358     }
   2359   } else {
   2360     for (var name in debugger_flags) {
   2361       var value = debugger_flags[name].getValue();
   2362       response.body.flags.push({ name: name, value: value });
   2363     }
   2364   }
   2365 }
   2366 
   2367 
   2368 DebugCommandProcessor.prototype.v8FlagsRequest_ = function(request, response) {
   2369   var flags = request.arguments.flags;
   2370   if (!flags) flags = '';
   2371   %SetFlags(flags);
   2372 };
   2373 
   2374 
   2375 DebugCommandProcessor.prototype.gcRequest_ = function(request, response) {
   2376   var type = request.arguments.type;
   2377   if (!type) type = 'all';
   2378 
   2379   var before = %GetHeapUsage();
   2380   %CollectGarbage(type);
   2381   var after = %GetHeapUsage();
   2382 
   2383   response.body = { "before": before, "after": after };
   2384 };
   2385 
   2386 
   2387 DebugCommandProcessor.prototype.lolCaptureRequest_ =
   2388     function(request, response) {
   2389   response.body = %CaptureLOL();
   2390 };
   2391 
   2392 
   2393 DebugCommandProcessor.prototype.lolDeleteRequest_ =
   2394     function(request, response) {
   2395   var id = request.arguments.id;
   2396   var result = %DeleteLOL(id);
   2397   if (result) {
   2398     response.body = { id: id };
   2399   } else {
   2400     response.failed('Failed to delete: live object list ' + id + ' not found.');
   2401   }
   2402 };
   2403 
   2404 
   2405 DebugCommandProcessor.prototype.lolDiffRequest_ = function(request, response) {
   2406   var id1 = request.arguments.id1;
   2407   var id2 = request.arguments.id2;
   2408   var verbose = request.arguments.verbose;
   2409   var filter = request.arguments.filter;
   2410   if (verbose === true) {
   2411     var start = request.arguments.start;
   2412     var count = request.arguments.count;
   2413     response.body = %DumpLOL(id1, id2, start, count, filter);
   2414   } else {
   2415     response.body = %SummarizeLOL(id1, id2, filter);
   2416   }
   2417 };
   2418 
   2419 
   2420 DebugCommandProcessor.prototype.lolGetIdRequest_ = function(request, response) {
   2421   var address = request.arguments.address;
   2422   response.body = {};
   2423   response.body.id = %GetLOLObjId(address);
   2424 };
   2425 
   2426 
   2427 DebugCommandProcessor.prototype.lolInfoRequest_ = function(request, response) {
   2428   var start = request.arguments.start;
   2429   var count = request.arguments.count;
   2430   response.body = %InfoLOL(start, count);
   2431 };
   2432 
   2433 
   2434 DebugCommandProcessor.prototype.lolResetRequest_ = function(request, response) {
   2435   %ResetLOL();
   2436 };
   2437 
   2438 
   2439 DebugCommandProcessor.prototype.lolRetainersRequest_ =
   2440     function(request, response) {
   2441   var id = request.arguments.id;
   2442   var verbose = request.arguments.verbose;
   2443   var start = request.arguments.start;
   2444   var count = request.arguments.count;
   2445   var filter = request.arguments.filter;
   2446 
   2447   response.body = %GetLOLObjRetainers(id, Mirror.prototype, verbose,
   2448                                       start, count, filter);
   2449 };
   2450 
   2451 
   2452 DebugCommandProcessor.prototype.lolPathRequest_ = function(request, response) {
   2453   var id1 = request.arguments.id1;
   2454   var id2 = request.arguments.id2;
   2455   response.body = {};
   2456   response.body.path = %GetLOLPath(id1, id2, Mirror.prototype);
   2457 };
   2458 
   2459 
   2460 DebugCommandProcessor.prototype.lolPrintRequest_ = function(request, response) {
   2461   var id = request.arguments.id;
   2462   response.body = {};
   2463   response.body.dump = %PrintLOLObj(id);
   2464 };
   2465 
   2466 
   2467 // Check whether the previously processed command caused the VM to become
   2468 // running.
   2469 DebugCommandProcessor.prototype.isRunning = function() {
   2470   return this.running_;
   2471 }
   2472 
   2473 
   2474 DebugCommandProcessor.prototype.systemBreak = function(cmd, args) {
   2475   return %SystemBreak();
   2476 };
   2477 
   2478 
   2479 function NumberToHex8Str(n) {
   2480   var r = "";
   2481   for (var i = 0; i < 8; ++i) {
   2482     var c = hexCharArray[n & 0x0F];  // hexCharArray is defined in uri.js
   2483     r = c + r;
   2484     n = n >>> 4;
   2485   }
   2486   return r;
   2487 };
   2488 
   2489 
   2490 /**
   2491  * Convert an Object to its debugger protocol representation. The representation
   2492  * may be serilized to a JSON object using JSON.stringify().
   2493  * This implementation simply runs through all string property names, converts
   2494  * each property value to a protocol value and adds the property to the result
   2495  * object. For type "object" the function will be called recursively. Note that
   2496  * circular structures will cause infinite recursion.
   2497  * @param {Object} object The object to format as protocol object.
   2498  * @param {MirrorSerializer} mirror_serializer The serializer to use if any
   2499  *     mirror objects are encountered.
   2500  * @return {Object} Protocol object value.
   2501  */
   2502 function ObjectToProtocolObject_(object, mirror_serializer) {
   2503   var content = {};
   2504   for (var key in object) {
   2505     // Only consider string keys.
   2506     if (typeof key == 'string') {
   2507       // Format the value based on its type.
   2508       var property_value_json = ValueToProtocolValue_(object[key],
   2509                                                       mirror_serializer);
   2510       // Add the property if relevant.
   2511       if (!IS_UNDEFINED(property_value_json)) {
   2512         content[key] = property_value_json;
   2513       }
   2514     }
   2515   }
   2516 
   2517   return content;
   2518 }
   2519 
   2520 
   2521 /**
   2522  * Convert an array to its debugger protocol representation. It will convert
   2523  * each array element to a protocol value.
   2524  * @param {Array} array The array to format as protocol array.
   2525  * @param {MirrorSerializer} mirror_serializer The serializer to use if any
   2526  *     mirror objects are encountered.
   2527  * @return {Array} Protocol array value.
   2528  */
   2529 function ArrayToProtocolArray_(array, mirror_serializer) {
   2530   var json = [];
   2531   for (var i = 0; i < array.length; i++) {
   2532     json.push(ValueToProtocolValue_(array[i], mirror_serializer));
   2533   }
   2534   return json;
   2535 }
   2536 
   2537 
   2538 /**
   2539  * Convert a value to its debugger protocol representation.
   2540  * @param {*} value The value to format as protocol value.
   2541  * @param {MirrorSerializer} mirror_serializer The serializer to use if any
   2542  *     mirror objects are encountered.
   2543  * @return {*} Protocol value.
   2544  */
   2545 function ValueToProtocolValue_(value, mirror_serializer) {
   2546   // Format the value based on its type.
   2547   var json;
   2548   switch (typeof value) {
   2549     case 'object':
   2550       if (value instanceof Mirror) {
   2551         json = mirror_serializer.serializeValue(value);
   2552       } else if (IS_ARRAY(value)){
   2553         json = ArrayToProtocolArray_(value, mirror_serializer);
   2554       } else {
   2555         json = ObjectToProtocolObject_(value, mirror_serializer);
   2556       }
   2557       break;
   2558 
   2559     case 'boolean':
   2560     case 'string':
   2561     case 'number':
   2562       json = value;
   2563       break
   2564 
   2565     default:
   2566       json = null;
   2567   }
   2568   return json;
   2569 }
   2570