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