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