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