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