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