| 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 | 
|---|