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