Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: src/debug-debugger.js

Issue 1265923002: Debugger: move implementation to a separate folder. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/debug.cc ('k') | src/debug/OWNERS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
27 // Types of exceptions that can be broken upon.
28 Debug.ExceptionBreak = { Caught : 0,
29 Uncaught: 1 };
30
31 // The different types of steps.
32 Debug.StepAction = { StepOut: 0,
33 StepNext: 1,
34 StepIn: 2,
35 StepMin: 3,
36 StepInMin: 4,
37 StepFrame: 5 };
38
39 // The different types of scripts matching enum ScriptType in objects.h.
40 Debug.ScriptType = { Native: 0,
41 Extension: 1,
42 Normal: 2 };
43
44 // The different types of script compilations matching enum
45 // Script::CompilationType in objects.h.
46 Debug.ScriptCompilationType = { Host: 0,
47 Eval: 1,
48 JSON: 2 };
49
50 // The different script break point types.
51 Debug.ScriptBreakPointType = { ScriptId: 0,
52 ScriptName: 1,
53 ScriptRegExp: 2 };
54
55 // The different types of breakpoint position alignments.
56 // Must match BreakPositionAlignment in debug.h.
57 Debug.BreakPositionAlignment = {
58 Statement: 0,
59 BreakPosition: 1
60 };
61
62 function ScriptTypeFlag(type) {
63 return (1 << type);
64 }
65
66 // Globals.
67 var next_response_seq = 0;
68 var next_break_point_number = 1;
69 var break_points = [];
70 var script_break_points = [];
71 var debugger_flags = {
72 breakPointsActive: {
73 value: true,
74 getValue: function() { return this.value; },
75 setValue: function(value) {
76 this.value = !!value;
77 %SetDisableBreak(!this.value);
78 }
79 },
80 breakOnCaughtException: {
81 getValue: function() { return Debug.isBreakOnException(); },
82 setValue: function(value) {
83 if (value) {
84 Debug.setBreakOnException();
85 } else {
86 Debug.clearBreakOnException();
87 }
88 }
89 },
90 breakOnUncaughtException: {
91 getValue: function() { return Debug.isBreakOnUncaughtException(); },
92 setValue: function(value) {
93 if (value) {
94 Debug.setBreakOnUncaughtException();
95 } else {
96 Debug.clearBreakOnUncaughtException();
97 }
98 }
99 },
100 };
101
102
103 // Create a new break point object and add it to the list of break points.
104 function MakeBreakPoint(source_position, opt_script_break_point) {
105 var break_point = new BreakPoint(source_position, opt_script_break_point);
106 break_points.push(break_point);
107 return break_point;
108 }
109
110
111 // Object representing a break point.
112 // NOTE: This object does not have a reference to the function having break
113 // point as this would cause function not to be garbage collected when it is
114 // not used any more. We do not want break points to keep functions alive.
115 function BreakPoint(source_position, opt_script_break_point) {
116 this.source_position_ = source_position;
117 if (opt_script_break_point) {
118 this.script_break_point_ = opt_script_break_point;
119 } else {
120 this.number_ = next_break_point_number++;
121 }
122 this.hit_count_ = 0;
123 this.active_ = true;
124 this.condition_ = null;
125 this.ignoreCount_ = 0;
126 }
127
128
129 BreakPoint.prototype.number = function() {
130 return this.number_;
131 };
132
133
134 BreakPoint.prototype.func = function() {
135 return this.func_;
136 };
137
138
139 BreakPoint.prototype.source_position = function() {
140 return this.source_position_;
141 };
142
143
144 BreakPoint.prototype.hit_count = function() {
145 return this.hit_count_;
146 };
147
148
149 BreakPoint.prototype.active = function() {
150 if (this.script_break_point()) {
151 return this.script_break_point().active();
152 }
153 return this.active_;
154 };
155
156
157 BreakPoint.prototype.condition = function() {
158 if (this.script_break_point() && this.script_break_point().condition()) {
159 return this.script_break_point().condition();
160 }
161 return this.condition_;
162 };
163
164
165 BreakPoint.prototype.ignoreCount = function() {
166 return this.ignoreCount_;
167 };
168
169
170 BreakPoint.prototype.script_break_point = function() {
171 return this.script_break_point_;
172 };
173
174
175 BreakPoint.prototype.enable = function() {
176 this.active_ = true;
177 };
178
179
180 BreakPoint.prototype.disable = function() {
181 this.active_ = false;
182 };
183
184
185 BreakPoint.prototype.setCondition = function(condition) {
186 this.condition_ = condition;
187 };
188
189
190 BreakPoint.prototype.setIgnoreCount = function(ignoreCount) {
191 this.ignoreCount_ = ignoreCount;
192 };
193
194
195 BreakPoint.prototype.isTriggered = function(exec_state) {
196 // Break point not active - not triggered.
197 if (!this.active()) return false;
198
199 // Check for conditional break point.
200 if (this.condition()) {
201 // If break point has condition try to evaluate it in the top frame.
202 try {
203 var mirror = exec_state.frame(0).evaluate(this.condition());
204 // If no sensible mirror or non true value break point not triggered.
205 if (!(mirror instanceof ValueMirror) ||
206 !builtins.$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 = builtins.$toNumber(opt_action);
929 var count = opt_count ? builtins.$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 = builtins.$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 = builtins.$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: ' + builtins.$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 = builtins.$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: "' + builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 = builtins.$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 }
OLDNEW
« no previous file with comments | « src/debug.cc ('k') | src/debug/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698