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