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