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

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

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

Powered by Google App Engine
This is Rietveld 408576698