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