1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// jsminify this file, js2c: jsmin 29 30// Touch the RegExp and Date functions to make sure that date-delay.js and 31// regexp-delay.js has been loaded. This is required as the mirrors use 32// functions within these files through the builtins object. 33RegExp; 34Date; 35 36 37// Handle id counters. 38var next_handle_ = 0; 39var next_transient_handle_ = -1; 40 41// Mirror cache. 42var mirror_cache_ = []; 43 44 45/** 46 * Clear the mirror handle cache. 47 */ 48function ClearMirrorCache() { 49 next_handle_ = 0; 50 mirror_cache_ = []; 51} 52 53 54/** 55 * Returns the mirror for a specified value or object. 56 * 57 * @param {value or Object} value the value or object to retreive the mirror for 58 * @param {boolean} transient indicate whether this object is transient and 59 * should not be added to the mirror cache. The default is not transient. 60 * @returns {Mirror} the mirror reflects the passed value or object 61 */ 62function MakeMirror(value, opt_transient) { 63 var mirror; 64 65 // Look for non transient mirrors in the mirror cache. 66 if (!opt_transient) { 67 for (id in mirror_cache_) { 68 mirror = mirror_cache_[id]; 69 if (mirror.value() === value) { 70 return mirror; 71 } 72 // Special check for NaN as NaN == NaN is false. 73 if (mirror.isNumber() && isNaN(mirror.value()) && 74 typeof value == 'number' && isNaN(value)) { 75 return mirror; 76 } 77 } 78 } 79 80 if (IS_UNDEFINED(value)) { 81 mirror = new UndefinedMirror(); 82 } else if (IS_NULL(value)) { 83 mirror = new NullMirror(); 84 } else if (IS_BOOLEAN(value)) { 85 mirror = new BooleanMirror(value); 86 } else if (IS_NUMBER(value)) { 87 mirror = new NumberMirror(value); 88 } else if (IS_STRING(value)) { 89 mirror = new StringMirror(value); 90 } else if (IS_ARRAY(value)) { 91 mirror = new ArrayMirror(value); 92 } else if (IS_DATE(value)) { 93 mirror = new DateMirror(value); 94 } else if (IS_FUNCTION(value)) { 95 mirror = new FunctionMirror(value); 96 } else if (IS_REGEXP(value)) { 97 mirror = new RegExpMirror(value); 98 } else if (IS_ERROR(value)) { 99 mirror = new ErrorMirror(value); 100 } else if (IS_SCRIPT(value)) { 101 mirror = new ScriptMirror(value); 102 } else { 103 mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient); 104 } 105 106 mirror_cache_[mirror.handle()] = mirror; 107 return mirror; 108} 109 110 111/** 112 * Returns the mirror for a specified mirror handle. 113 * 114 * @param {number} handle the handle to find the mirror for 115 * @returns {Mirror or undefiend} the mirror with the requested handle or 116 * undefined if no mirror with the requested handle was found 117 */ 118function LookupMirror(handle) { 119 return mirror_cache_[handle]; 120} 121 122 123/** 124 * Returns the mirror for the undefined value. 125 * 126 * @returns {Mirror} the mirror reflects the undefined value 127 */ 128function GetUndefinedMirror() { 129 return MakeMirror(void 0); 130} 131 132 133/** 134 * Inherit the prototype methods from one constructor into another. 135 * 136 * The Function.prototype.inherits from lang.js rewritten as a standalone 137 * function (not on Function.prototype). NOTE: If this file is to be loaded 138 * during bootstrapping this function needs to be revritten using some native 139 * functions as prototype setup using normal JavaScript does not work as 140 * expected during bootstrapping (see mirror.js in r114903). 141 * 142 * @param {function} ctor Constructor function which needs to inherit the 143 * prototype 144 * @param {function} superCtor Constructor function to inherit prototype from 145 */ 146function inherits(ctor, superCtor) { 147 var tempCtor = function(){}; 148 tempCtor.prototype = superCtor.prototype; 149 ctor.super_ = superCtor.prototype; 150 ctor.prototype = new tempCtor(); 151 ctor.prototype.constructor = ctor; 152} 153 154 155// Type names of the different mirrors. 156const UNDEFINED_TYPE = 'undefined'; 157const NULL_TYPE = 'null'; 158const BOOLEAN_TYPE = 'boolean'; 159const NUMBER_TYPE = 'number'; 160const STRING_TYPE = 'string'; 161const OBJECT_TYPE = 'object'; 162const FUNCTION_TYPE = 'function'; 163const REGEXP_TYPE = 'regexp'; 164const ERROR_TYPE = 'error'; 165const PROPERTY_TYPE = 'property'; 166const FRAME_TYPE = 'frame'; 167const SCRIPT_TYPE = 'script'; 168const CONTEXT_TYPE = 'context'; 169const SCOPE_TYPE = 'scope'; 170 171// Maximum length when sending strings through the JSON protocol. 172const kMaxProtocolStringLength = 80; 173 174// Different kind of properties. 175PropertyKind = {}; 176PropertyKind.Named = 1; 177PropertyKind.Indexed = 2; 178 179 180// A copy of the PropertyType enum from global.h 181PropertyType = {}; 182PropertyType.Normal = 0; 183PropertyType.Field = 1; 184PropertyType.ConstantFunction = 2; 185PropertyType.Callbacks = 3; 186PropertyType.Interceptor = 4; 187PropertyType.MapTransition = 5; 188PropertyType.ConstantTransition = 6; 189PropertyType.NullDescriptor = 7; 190 191 192// Different attributes for a property. 193PropertyAttribute = {}; 194PropertyAttribute.None = NONE; 195PropertyAttribute.ReadOnly = READ_ONLY; 196PropertyAttribute.DontEnum = DONT_ENUM; 197PropertyAttribute.DontDelete = DONT_DELETE; 198 199 200// A copy of the scope types from runtime.cc. 201ScopeType = { Global: 0, 202 Local: 1, 203 With: 2, 204 Closure: 3 }; 205 206 207// Mirror hierarchy: 208// - Mirror 209// - ValueMirror 210// - UndefinedMirror 211// - NullMirror 212// - NumberMirror 213// - StringMirror 214// - ObjectMirror 215// - FunctionMirror 216// - UnresolvedFunctionMirror 217// - ArrayMirror 218// - DateMirror 219// - RegExpMirror 220// - ErrorMirror 221// - PropertyMirror 222// - FrameMirror 223// - ScriptMirror 224 225 226/** 227 * Base class for all mirror objects. 228 * @param {string} type The type of the mirror 229 * @constructor 230 */ 231function Mirror(type) { 232 this.type_ = type; 233}; 234 235 236Mirror.prototype.type = function() { 237 return this.type_; 238}; 239 240 241/** 242 * Check whether the mirror reflects a value. 243 * @returns {boolean} True if the mirror reflects a value. 244 */ 245Mirror.prototype.isValue = function() { 246 return this instanceof ValueMirror; 247} 248 249 250/** 251 * Check whether the mirror reflects the undefined value. 252 * @returns {boolean} True if the mirror reflects the undefined value. 253 */ 254Mirror.prototype.isUndefined = function() { 255 return this instanceof UndefinedMirror; 256} 257 258 259/** 260 * Check whether the mirror reflects the null value. 261 * @returns {boolean} True if the mirror reflects the null value 262 */ 263Mirror.prototype.isNull = function() { 264 return this instanceof NullMirror; 265} 266 267 268/** 269 * Check whether the mirror reflects a boolean value. 270 * @returns {boolean} True if the mirror reflects a boolean value 271 */ 272Mirror.prototype.isBoolean = function() { 273 return this instanceof BooleanMirror; 274} 275 276 277/** 278 * Check whether the mirror reflects a number value. 279 * @returns {boolean} True if the mirror reflects a number value 280 */ 281Mirror.prototype.isNumber = function() { 282 return this instanceof NumberMirror; 283} 284 285 286/** 287 * Check whether the mirror reflects a string value. 288 * @returns {boolean} True if the mirror reflects a string value 289 */ 290Mirror.prototype.isString = function() { 291 return this instanceof StringMirror; 292} 293 294 295/** 296 * Check whether the mirror reflects an object. 297 * @returns {boolean} True if the mirror reflects an object 298 */ 299Mirror.prototype.isObject = function() { 300 return this instanceof ObjectMirror; 301} 302 303 304/** 305 * Check whether the mirror reflects a function. 306 * @returns {boolean} True if the mirror reflects a function 307 */ 308Mirror.prototype.isFunction = function() { 309 return this instanceof FunctionMirror; 310} 311 312 313/** 314 * Check whether the mirror reflects an unresolved function. 315 * @returns {boolean} True if the mirror reflects an unresolved function 316 */ 317Mirror.prototype.isUnresolvedFunction = function() { 318 return this instanceof UnresolvedFunctionMirror; 319} 320 321 322/** 323 * Check whether the mirror reflects an array. 324 * @returns {boolean} True if the mirror reflects an array 325 */ 326Mirror.prototype.isArray = function() { 327 return this instanceof ArrayMirror; 328} 329 330 331/** 332 * Check whether the mirror reflects a date. 333 * @returns {boolean} True if the mirror reflects a date 334 */ 335Mirror.prototype.isDate = function() { 336 return this instanceof DateMirror; 337} 338 339 340/** 341 * Check whether the mirror reflects a regular expression. 342 * @returns {boolean} True if the mirror reflects a regular expression 343 */ 344Mirror.prototype.isRegExp = function() { 345 return this instanceof RegExpMirror; 346} 347 348 349/** 350 * Check whether the mirror reflects an error. 351 * @returns {boolean} True if the mirror reflects an error 352 */ 353Mirror.prototype.isError = function() { 354 return this instanceof ErrorMirror; 355} 356 357 358/** 359 * Check whether the mirror reflects a property. 360 * @returns {boolean} True if the mirror reflects a property 361 */ 362Mirror.prototype.isProperty = function() { 363 return this instanceof PropertyMirror; 364} 365 366 367/** 368 * Check whether the mirror reflects a stack frame. 369 * @returns {boolean} True if the mirror reflects a stack frame 370 */ 371Mirror.prototype.isFrame = function() { 372 return this instanceof FrameMirror; 373} 374 375 376/** 377 * Check whether the mirror reflects a script. 378 * @returns {boolean} True if the mirror reflects a script 379 */ 380Mirror.prototype.isScript = function() { 381 return this instanceof ScriptMirror; 382} 383 384 385/** 386 * Check whether the mirror reflects a context. 387 * @returns {boolean} True if the mirror reflects a context 388 */ 389Mirror.prototype.isContext = function() { 390 return this instanceof ContextMirror; 391} 392 393 394/** 395 * Check whether the mirror reflects a scope. 396 * @returns {boolean} True if the mirror reflects a scope 397 */ 398Mirror.prototype.isScope = function() { 399 return this instanceof ScopeMirror; 400} 401 402 403/** 404 * Allocate a handle id for this object. 405 */ 406Mirror.prototype.allocateHandle_ = function() { 407 this.handle_ = next_handle_++; 408} 409 410 411/** 412 * Allocate a transient handle id for this object. Transient handles are 413 * negative. 414 */ 415Mirror.prototype.allocateTransientHandle_ = function() { 416 this.handle_ = next_transient_handle_--; 417} 418 419 420Mirror.prototype.toText = function() { 421 // Simpel to text which is used when on specialization in subclass. 422 return "#<" + builtins.GetInstanceName(this.constructor.name) + ">"; 423} 424 425 426/** 427 * Base class for all value mirror objects. 428 * @param {string} type The type of the mirror 429 * @param {value} value The value reflected by this mirror 430 * @param {boolean} transient indicate whether this object is transient with a 431 * transient handle 432 * @constructor 433 * @extends Mirror 434 */ 435function ValueMirror(type, value, transient) { 436 Mirror.call(this, type); 437 this.value_ = value; 438 if (!transient) { 439 this.allocateHandle_(); 440 } else { 441 this.allocateTransientHandle_(); 442 } 443} 444inherits(ValueMirror, Mirror); 445 446 447Mirror.prototype.handle = function() { 448 return this.handle_; 449}; 450 451 452/** 453 * Check whether this is a primitive value. 454 * @return {boolean} True if the mirror reflects a primitive value 455 */ 456ValueMirror.prototype.isPrimitive = function() { 457 var type = this.type(); 458 return type === 'undefined' || 459 type === 'null' || 460 type === 'boolean' || 461 type === 'number' || 462 type === 'string'; 463}; 464 465 466/** 467 * Get the actual value reflected by this mirror. 468 * @return {value} The value reflected by this mirror 469 */ 470ValueMirror.prototype.value = function() { 471 return this.value_; 472}; 473 474 475/** 476 * Mirror object for Undefined. 477 * @constructor 478 * @extends ValueMirror 479 */ 480function UndefinedMirror() { 481 ValueMirror.call(this, UNDEFINED_TYPE, void 0); 482} 483inherits(UndefinedMirror, ValueMirror); 484 485 486UndefinedMirror.prototype.toText = function() { 487 return 'undefined'; 488} 489 490 491/** 492 * Mirror object for null. 493 * @constructor 494 * @extends ValueMirror 495 */ 496function NullMirror() { 497 ValueMirror.call(this, NULL_TYPE, null); 498} 499inherits(NullMirror, ValueMirror); 500 501 502NullMirror.prototype.toText = function() { 503 return 'null'; 504} 505 506 507/** 508 * Mirror object for boolean values. 509 * @param {boolean} value The boolean value reflected by this mirror 510 * @constructor 511 * @extends ValueMirror 512 */ 513function BooleanMirror(value) { 514 ValueMirror.call(this, BOOLEAN_TYPE, value); 515} 516inherits(BooleanMirror, ValueMirror); 517 518 519BooleanMirror.prototype.toText = function() { 520 return this.value_ ? 'true' : 'false'; 521} 522 523 524/** 525 * Mirror object for number values. 526 * @param {number} value The number value reflected by this mirror 527 * @constructor 528 * @extends ValueMirror 529 */ 530function NumberMirror(value) { 531 ValueMirror.call(this, NUMBER_TYPE, value); 532} 533inherits(NumberMirror, ValueMirror); 534 535 536NumberMirror.prototype.toText = function() { 537 return %NumberToString(this.value_); 538} 539 540 541/** 542 * Mirror object for string values. 543 * @param {string} value The string value reflected by this mirror 544 * @constructor 545 * @extends ValueMirror 546 */ 547function StringMirror(value) { 548 ValueMirror.call(this, STRING_TYPE, value); 549} 550inherits(StringMirror, ValueMirror); 551 552 553StringMirror.prototype.length = function() { 554 return this.value_.length; 555}; 556 557 558StringMirror.prototype.toText = function() { 559 if (this.length() > kMaxProtocolStringLength) { 560 return this.value_.substring(0, kMaxProtocolStringLength) + 561 '... (length: ' + this.length() + ')'; 562 } else { 563 return this.value_; 564 } 565} 566 567 568/** 569 * Mirror object for objects. 570 * @param {object} value The object reflected by this mirror 571 * @param {boolean} transient indicate whether this object is transient with a 572 * transient handle 573 * @constructor 574 * @extends ValueMirror 575 */ 576function ObjectMirror(value, type, transient) { 577 ValueMirror.call(this, type || OBJECT_TYPE, value, transient); 578} 579inherits(ObjectMirror, ValueMirror); 580 581 582ObjectMirror.prototype.className = function() { 583 return %_ClassOf(this.value_); 584}; 585 586 587ObjectMirror.prototype.constructorFunction = function() { 588 return MakeMirror(%DebugGetProperty(this.value_, 'constructor')); 589}; 590 591 592ObjectMirror.prototype.prototypeObject = function() { 593 return MakeMirror(%DebugGetProperty(this.value_, 'prototype')); 594}; 595 596 597ObjectMirror.prototype.protoObject = function() { 598 return MakeMirror(%DebugGetPrototype(this.value_)); 599}; 600 601 602ObjectMirror.prototype.hasNamedInterceptor = function() { 603 // Get information on interceptors for this object. 604 var x = %DebugInterceptorInfo(this.value_); 605 return (x & 2) != 0; 606}; 607 608 609ObjectMirror.prototype.hasIndexedInterceptor = function() { 610 // Get information on interceptors for this object. 611 var x = %DebugInterceptorInfo(this.value_); 612 return (x & 1) != 0; 613}; 614 615 616/** 617 * Return the property names for this object. 618 * @param {number} kind Indicate whether named, indexed or both kinds of 619 * properties are requested 620 * @param {number} limit Limit the number of names returend to the specified 621 value 622 * @return {Array} Property names for this object 623 */ 624ObjectMirror.prototype.propertyNames = function(kind, limit) { 625 // Find kind and limit and allocate array for the result 626 kind = kind || PropertyKind.Named | PropertyKind.Indexed; 627 628 var propertyNames; 629 var elementNames; 630 var total = 0; 631 632 // Find all the named properties. 633 if (kind & PropertyKind.Named) { 634 // Get the local property names. 635 propertyNames = %DebugLocalPropertyNames(this.value_); 636 total += propertyNames.length; 637 638 // Get names for named interceptor properties if any. 639 if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) { 640 var namedInterceptorNames = 641 %DebugNamedInterceptorPropertyNames(this.value_); 642 if (namedInterceptorNames) { 643 propertyNames = propertyNames.concat(namedInterceptorNames); 644 total += namedInterceptorNames.length; 645 } 646 } 647 } 648 649 // Find all the indexed properties. 650 if (kind & PropertyKind.Indexed) { 651 // Get the local element names. 652 elementNames = %DebugLocalElementNames(this.value_); 653 total += elementNames.length; 654 655 // Get names for indexed interceptor properties. 656 if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) { 657 var indexedInterceptorNames = 658 %DebugIndexedInterceptorElementNames(this.value_); 659 if (indexedInterceptorNames) { 660 elementNames = elementNames.concat(indexedInterceptorNames); 661 total += indexedInterceptorNames.length; 662 } 663 } 664 } 665 limit = Math.min(limit || total, total); 666 667 var names = new Array(limit); 668 var index = 0; 669 670 // Copy names for named properties. 671 if (kind & PropertyKind.Named) { 672 for (var i = 0; index < limit && i < propertyNames.length; i++) { 673 names[index++] = propertyNames[i]; 674 } 675 } 676 677 // Copy names for indexed properties. 678 if (kind & PropertyKind.Indexed) { 679 for (var i = 0; index < limit && i < elementNames.length; i++) { 680 names[index++] = elementNames[i]; 681 } 682 } 683 684 return names; 685}; 686 687 688/** 689 * Return the properties for this object as an array of PropertyMirror objects. 690 * @param {number} kind Indicate whether named, indexed or both kinds of 691 * properties are requested 692 * @param {number} limit Limit the number of properties returend to the 693 specified value 694 * @return {Array} Property mirrors for this object 695 */ 696ObjectMirror.prototype.properties = function(kind, limit) { 697 var names = this.propertyNames(kind, limit); 698 var properties = new Array(names.length); 699 for (var i = 0; i < names.length; i++) { 700 properties[i] = this.property(names[i]); 701 } 702 703 return properties; 704}; 705 706 707ObjectMirror.prototype.property = function(name) { 708 var details = %DebugGetPropertyDetails(this.value_, %ToString(name)); 709 if (details) { 710 return new PropertyMirror(this, name, details); 711 } 712 713 // Nothing found. 714 return GetUndefinedMirror(); 715}; 716 717 718 719/** 720 * Try to find a property from its value. 721 * @param {Mirror} value The property value to look for 722 * @return {PropertyMirror} The property with the specified value. If no 723 * property was found with the specified value UndefinedMirror is returned 724 */ 725ObjectMirror.prototype.lookupProperty = function(value) { 726 var properties = this.properties(); 727 728 // Look for property value in properties. 729 for (var i = 0; i < properties.length; i++) { 730 731 // Skip properties which are defined through assessors. 732 var property = properties[i]; 733 if (property.propertyType() != PropertyType.Callbacks) { 734 if (%_ObjectEquals(property.value_, value.value_)) { 735 return property; 736 } 737 } 738 } 739 740 // Nothing found. 741 return GetUndefinedMirror(); 742}; 743 744 745/** 746 * Returns objects which has direct references to this object 747 * @param {number} opt_max_objects Optional parameter specifying the maximum 748 * number of referencing objects to return. 749 * @return {Array} The objects which has direct references to this object. 750 */ 751ObjectMirror.prototype.referencedBy = function(opt_max_objects) { 752 // Find all objects with direct references to this object. 753 var result = %DebugReferencedBy(this.value_, 754 Mirror.prototype, opt_max_objects || 0); 755 756 // Make mirrors for all the references found. 757 for (var i = 0; i < result.length; i++) { 758 result[i] = MakeMirror(result[i]); 759 } 760 761 return result; 762}; 763 764 765ObjectMirror.prototype.toText = function() { 766 var name; 767 var ctor = this.constructorFunction(); 768 if (ctor.isUndefined()) { 769 name = this.className(); 770 } else { 771 name = ctor.name(); 772 if (!name) { 773 name = this.className(); 774 } 775 } 776 return '#<' + builtins.GetInstanceName(name) + '>'; 777}; 778 779 780/** 781 * Mirror object for functions. 782 * @param {function} value The function object reflected by this mirror. 783 * @constructor 784 * @extends ObjectMirror 785 */ 786function FunctionMirror(value) { 787 ObjectMirror.call(this, value, FUNCTION_TYPE); 788 this.resolved_ = true; 789} 790inherits(FunctionMirror, ObjectMirror); 791 792 793/** 794 * Returns whether the function is resolved. 795 * @return {boolean} True if the function is resolved. Unresolved functions can 796 * only originate as functions from stack frames 797 */ 798FunctionMirror.prototype.resolved = function() { 799 return this.resolved_; 800}; 801 802 803/** 804 * Returns the name of the function. 805 * @return {string} Name of the function 806 */ 807FunctionMirror.prototype.name = function() { 808 return %FunctionGetName(this.value_); 809}; 810 811 812/** 813 * Returns the inferred name of the function. 814 * @return {string} Name of the function 815 */ 816FunctionMirror.prototype.inferredName = function() { 817 return %FunctionGetInferredName(this.value_); 818}; 819 820 821/** 822 * Returns the source code for the function. 823 * @return {string or undefined} The source code for the function. If the 824 * function is not resolved undefined will be returned. 825 */ 826FunctionMirror.prototype.source = function() { 827 // Return source if function is resolved. Otherwise just fall through to 828 // return undefined. 829 if (this.resolved()) { 830 return builtins.FunctionSourceString(this.value_); 831 } 832}; 833 834 835/** 836 * Returns the script object for the function. 837 * @return {ScriptMirror or undefined} Script object for the function or 838 * undefined if the function has no script 839 */ 840FunctionMirror.prototype.script = function() { 841 // Return script if function is resolved. Otherwise just fall through 842 // to return undefined. 843 if (this.resolved()) { 844 var script = %FunctionGetScript(this.value_); 845 if (script) { 846 return MakeMirror(script); 847 } 848 } 849}; 850 851 852/** 853 * Returns objects constructed by this function. 854 * @param {number} opt_max_instances Optional parameter specifying the maximum 855 * number of instances to return. 856 * @return {Array or undefined} The objects constructed by this function. 857 */ 858FunctionMirror.prototype.constructedBy = function(opt_max_instances) { 859 if (this.resolved()) { 860 // Find all objects constructed from this function. 861 var result = %DebugConstructedBy(this.value_, opt_max_instances || 0); 862 863 // Make mirrors for all the instances found. 864 for (var i = 0; i < result.length; i++) { 865 result[i] = MakeMirror(result[i]); 866 } 867 868 return result; 869 } else { 870 return []; 871 } 872}; 873 874 875FunctionMirror.prototype.toText = function() { 876 return this.source(); 877} 878 879 880/** 881 * Mirror object for unresolved functions. 882 * @param {string} value The name for the unresolved function reflected by this 883 * mirror. 884 * @constructor 885 * @extends ObjectMirror 886 */ 887function UnresolvedFunctionMirror(value) { 888 // Construct this using the ValueMirror as an unresolved function is not a 889 // real object but just a string. 890 ValueMirror.call(this, FUNCTION_TYPE, value); 891 this.propertyCount_ = 0; 892 this.elementCount_ = 0; 893 this.resolved_ = false; 894} 895inherits(UnresolvedFunctionMirror, FunctionMirror); 896 897 898UnresolvedFunctionMirror.prototype.className = function() { 899 return 'Function'; 900}; 901 902 903UnresolvedFunctionMirror.prototype.constructorFunction = function() { 904 return GetUndefinedMirror(); 905}; 906 907 908UnresolvedFunctionMirror.prototype.prototypeObject = function() { 909 return GetUndefinedMirror(); 910}; 911 912 913UnresolvedFunctionMirror.prototype.protoObject = function() { 914 return GetUndefinedMirror(); 915}; 916 917 918UnresolvedFunctionMirror.prototype.name = function() { 919 return this.value_; 920}; 921 922 923UnresolvedFunctionMirror.prototype.inferredName = function() { 924 return undefined; 925}; 926 927 928UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) { 929 return []; 930} 931 932 933/** 934 * Mirror object for arrays. 935 * @param {Array} value The Array object reflected by this mirror 936 * @constructor 937 * @extends ObjectMirror 938 */ 939function ArrayMirror(value) { 940 ObjectMirror.call(this, value); 941} 942inherits(ArrayMirror, ObjectMirror); 943 944 945ArrayMirror.prototype.length = function() { 946 return this.value_.length; 947}; 948 949 950ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) { 951 var from_index = opt_from_index || 0; 952 var to_index = opt_to_index || this.length() - 1; 953 if (from_index > to_index) return new Array(); 954 var values = new Array(to_index - from_index + 1); 955 for (var i = from_index; i <= to_index; i++) { 956 var details = %DebugGetPropertyDetails(this.value_, %ToString(i)); 957 var value; 958 if (details) { 959 value = new PropertyMirror(this, i, details); 960 } else { 961 value = GetUndefinedMirror(); 962 } 963 values[i - from_index] = value; 964 } 965 return values; 966} 967 968 969/** 970 * Mirror object for dates. 971 * @param {Date} value The Date object reflected by this mirror 972 * @constructor 973 * @extends ObjectMirror 974 */ 975function DateMirror(value) { 976 ObjectMirror.call(this, value); 977} 978inherits(DateMirror, ObjectMirror); 979 980 981DateMirror.prototype.toText = function() { 982 var s = JSON.stringify(this.value_); 983 return s.substring(1, s.length - 1); // cut quotes 984} 985 986 987/** 988 * Mirror object for regular expressions. 989 * @param {RegExp} value The RegExp object reflected by this mirror 990 * @constructor 991 * @extends ObjectMirror 992 */ 993function RegExpMirror(value) { 994 ObjectMirror.call(this, value, REGEXP_TYPE); 995} 996inherits(RegExpMirror, ObjectMirror); 997 998 999/** 1000 * Returns the source to the regular expression. 1001 * @return {string or undefined} The source to the regular expression 1002 */ 1003RegExpMirror.prototype.source = function() { 1004 return this.value_.source; 1005}; 1006 1007 1008/** 1009 * Returns whether this regular expression has the global (g) flag set. 1010 * @return {boolean} Value of the global flag 1011 */ 1012RegExpMirror.prototype.global = function() { 1013 return this.value_.global; 1014}; 1015 1016 1017/** 1018 * Returns whether this regular expression has the ignore case (i) flag set. 1019 * @return {boolean} Value of the ignore case flag 1020 */ 1021RegExpMirror.prototype.ignoreCase = function() { 1022 return this.value_.ignoreCase; 1023}; 1024 1025 1026/** 1027 * Returns whether this regular expression has the multiline (m) flag set. 1028 * @return {boolean} Value of the multiline flag 1029 */ 1030RegExpMirror.prototype.multiline = function() { 1031 return this.value_.multiline; 1032}; 1033 1034 1035RegExpMirror.prototype.toText = function() { 1036 // Simpel to text which is used when on specialization in subclass. 1037 return "/" + this.source() + "/"; 1038} 1039 1040 1041/** 1042 * Mirror object for error objects. 1043 * @param {Error} value The error object reflected by this mirror 1044 * @constructor 1045 * @extends ObjectMirror 1046 */ 1047function ErrorMirror(value) { 1048 ObjectMirror.call(this, value, ERROR_TYPE); 1049} 1050inherits(ErrorMirror, ObjectMirror); 1051 1052 1053/** 1054 * Returns the message for this eror object. 1055 * @return {string or undefined} The message for this eror object 1056 */ 1057ErrorMirror.prototype.message = function() { 1058 return this.value_.message; 1059}; 1060 1061 1062ErrorMirror.prototype.toText = function() { 1063 // Use the same text representation as in messages.js. 1064 var text; 1065 try { 1066 str = builtins.ToDetailString(this.value_); 1067 } catch (e) { 1068 str = '#<an Error>'; 1069 } 1070 return str; 1071} 1072 1073 1074/** 1075 * Base mirror object for properties. 1076 * @param {ObjectMirror} mirror The mirror object having this property 1077 * @param {string} name The name of the property 1078 * @param {Array} details Details about the property 1079 * @constructor 1080 * @extends Mirror 1081 */ 1082function PropertyMirror(mirror, name, details) { 1083 Mirror.call(this, PROPERTY_TYPE); 1084 this.mirror_ = mirror; 1085 this.name_ = name; 1086 this.value_ = details[0]; 1087 this.details_ = details[1]; 1088 if (details.length > 2) { 1089 this.exception_ = details[2] 1090 this.getter_ = details[3]; 1091 this.setter_ = details[4]; 1092 } 1093} 1094inherits(PropertyMirror, Mirror); 1095 1096 1097PropertyMirror.prototype.isReadOnly = function() { 1098 return (this.attributes() & PropertyAttribute.ReadOnly) != 0; 1099} 1100 1101 1102PropertyMirror.prototype.isEnum = function() { 1103 return (this.attributes() & PropertyAttribute.DontEnum) == 0; 1104} 1105 1106 1107PropertyMirror.prototype.canDelete = function() { 1108 return (this.attributes() & PropertyAttribute.DontDelete) == 0; 1109} 1110 1111 1112PropertyMirror.prototype.name = function() { 1113 return this.name_; 1114} 1115 1116 1117PropertyMirror.prototype.isIndexed = function() { 1118 for (var i = 0; i < this.name_.length; i++) { 1119 if (this.name_[i] < '0' || '9' < this.name_[i]) { 1120 return false; 1121 } 1122 } 1123 return true; 1124} 1125 1126 1127PropertyMirror.prototype.value = function() { 1128 return MakeMirror(this.value_, false); 1129} 1130 1131 1132/** 1133 * Returns whether this property value is an exception. 1134 * @return {booolean} True if this property value is an exception 1135 */ 1136PropertyMirror.prototype.isException = function() { 1137 return this.exception_ ? true : false; 1138} 1139 1140 1141PropertyMirror.prototype.attributes = function() { 1142 return %DebugPropertyAttributesFromDetails(this.details_); 1143} 1144 1145 1146PropertyMirror.prototype.propertyType = function() { 1147 return %DebugPropertyTypeFromDetails(this.details_); 1148} 1149 1150 1151PropertyMirror.prototype.insertionIndex = function() { 1152 return %DebugPropertyIndexFromDetails(this.details_); 1153} 1154 1155 1156/** 1157 * Returns whether this property has a getter defined through __defineGetter__. 1158 * @return {booolean} True if this property has a getter 1159 */ 1160PropertyMirror.prototype.hasGetter = function() { 1161 return this.getter_ ? true : false; 1162} 1163 1164 1165/** 1166 * Returns whether this property has a setter defined through __defineSetter__. 1167 * @return {booolean} True if this property has a setter 1168 */ 1169PropertyMirror.prototype.hasSetter = function() { 1170 return this.setter_ ? true : false; 1171} 1172 1173 1174/** 1175 * Returns the getter for this property defined through __defineGetter__. 1176 * @return {Mirror} FunctionMirror reflecting the getter function or 1177 * UndefinedMirror if there is no getter for this property 1178 */ 1179PropertyMirror.prototype.getter = function() { 1180 if (this.hasGetter()) { 1181 return MakeMirror(this.getter_); 1182 } else { 1183 return GetUndefinedMirror(); 1184 } 1185} 1186 1187 1188/** 1189 * Returns the setter for this property defined through __defineSetter__. 1190 * @return {Mirror} FunctionMirror reflecting the setter function or 1191 * UndefinedMirror if there is no setter for this property 1192 */ 1193PropertyMirror.prototype.setter = function() { 1194 if (this.hasSetter()) { 1195 return MakeMirror(this.setter_); 1196 } else { 1197 return GetUndefinedMirror(); 1198 } 1199} 1200 1201 1202/** 1203 * Returns whether this property is natively implemented by the host or a set 1204 * through JavaScript code. 1205 * @return {boolean} True if the property is 1206 * UndefinedMirror if there is no setter for this property 1207 */ 1208PropertyMirror.prototype.isNative = function() { 1209 return (this.propertyType() == PropertyType.Interceptor) || 1210 ((this.propertyType() == PropertyType.Callbacks) && 1211 !this.hasGetter() && !this.hasSetter()); 1212} 1213 1214 1215const kFrameDetailsFrameIdIndex = 0; 1216const kFrameDetailsReceiverIndex = 1; 1217const kFrameDetailsFunctionIndex = 2; 1218const kFrameDetailsArgumentCountIndex = 3; 1219const kFrameDetailsLocalCountIndex = 4; 1220const kFrameDetailsSourcePositionIndex = 5; 1221const kFrameDetailsConstructCallIndex = 6; 1222const kFrameDetailsDebuggerFrameIndex = 7; 1223const kFrameDetailsFirstDynamicIndex = 8; 1224 1225const kFrameDetailsNameIndex = 0; 1226const kFrameDetailsValueIndex = 1; 1227const kFrameDetailsNameValueSize = 2; 1228 1229/** 1230 * Wrapper for the frame details information retreived from the VM. The frame 1231 * details from the VM is an array with the following content. See runtime.cc 1232 * Runtime_GetFrameDetails. 1233 * 0: Id 1234 * 1: Receiver 1235 * 2: Function 1236 * 3: Argument count 1237 * 4: Local count 1238 * 5: Source position 1239 * 6: Construct call 1240 * Arguments name, value 1241 * Locals name, value 1242 * @param {number} break_id Current break id 1243 * @param {number} index Frame number 1244 * @constructor 1245 */ 1246function FrameDetails(break_id, index) { 1247 this.break_id_ = break_id; 1248 this.details_ = %GetFrameDetails(break_id, index); 1249} 1250 1251 1252FrameDetails.prototype.frameId = function() { 1253 %CheckExecutionState(this.break_id_); 1254 return this.details_[kFrameDetailsFrameIdIndex]; 1255} 1256 1257 1258FrameDetails.prototype.receiver = function() { 1259 %CheckExecutionState(this.break_id_); 1260 return this.details_[kFrameDetailsReceiverIndex]; 1261} 1262 1263 1264FrameDetails.prototype.func = function() { 1265 %CheckExecutionState(this.break_id_); 1266 return this.details_[kFrameDetailsFunctionIndex]; 1267} 1268 1269 1270FrameDetails.prototype.isConstructCall = function() { 1271 %CheckExecutionState(this.break_id_); 1272 return this.details_[kFrameDetailsConstructCallIndex]; 1273} 1274 1275 1276FrameDetails.prototype.isDebuggerFrame = function() { 1277 %CheckExecutionState(this.break_id_); 1278 return this.details_[kFrameDetailsDebuggerFrameIndex]; 1279} 1280 1281 1282FrameDetails.prototype.argumentCount = function() { 1283 %CheckExecutionState(this.break_id_); 1284 return this.details_[kFrameDetailsArgumentCountIndex]; 1285} 1286 1287 1288FrameDetails.prototype.argumentName = function(index) { 1289 %CheckExecutionState(this.break_id_); 1290 if (index >= 0 && index < this.argumentCount()) { 1291 return this.details_[kFrameDetailsFirstDynamicIndex + 1292 index * kFrameDetailsNameValueSize + 1293 kFrameDetailsNameIndex] 1294 } 1295} 1296 1297 1298FrameDetails.prototype.argumentValue = function(index) { 1299 %CheckExecutionState(this.break_id_); 1300 if (index >= 0 && index < this.argumentCount()) { 1301 return this.details_[kFrameDetailsFirstDynamicIndex + 1302 index * kFrameDetailsNameValueSize + 1303 kFrameDetailsValueIndex] 1304 } 1305} 1306 1307 1308FrameDetails.prototype.localCount = function() { 1309 %CheckExecutionState(this.break_id_); 1310 return this.details_[kFrameDetailsLocalCountIndex]; 1311} 1312 1313 1314FrameDetails.prototype.sourcePosition = function() { 1315 %CheckExecutionState(this.break_id_); 1316 return this.details_[kFrameDetailsSourcePositionIndex]; 1317} 1318 1319 1320FrameDetails.prototype.localName = function(index) { 1321 %CheckExecutionState(this.break_id_); 1322 if (index >= 0 && index < this.localCount()) { 1323 var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize 1324 return this.details_[locals_offset + 1325 index * kFrameDetailsNameValueSize + 1326 kFrameDetailsNameIndex] 1327 } 1328} 1329 1330 1331FrameDetails.prototype.localValue = function(index) { 1332 %CheckExecutionState(this.break_id_); 1333 if (index >= 0 && index < this.localCount()) { 1334 var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize 1335 return this.details_[locals_offset + 1336 index * kFrameDetailsNameValueSize + 1337 kFrameDetailsValueIndex] 1338 } 1339} 1340 1341 1342FrameDetails.prototype.scopeCount = function() { 1343 return %GetScopeCount(this.break_id_, this.frameId()); 1344} 1345 1346 1347/** 1348 * Mirror object for stack frames. 1349 * @param {number} break_id The break id in the VM for which this frame is 1350 valid 1351 * @param {number} index The frame index (top frame is index 0) 1352 * @constructor 1353 * @extends Mirror 1354 */ 1355function FrameMirror(break_id, index) { 1356 Mirror.call(this, FRAME_TYPE); 1357 this.break_id_ = break_id; 1358 this.index_ = index; 1359 this.details_ = new FrameDetails(break_id, index); 1360} 1361inherits(FrameMirror, Mirror); 1362 1363 1364FrameMirror.prototype.index = function() { 1365 return this.index_; 1366}; 1367 1368 1369FrameMirror.prototype.func = function() { 1370 // Get the function for this frame from the VM. 1371 var f = this.details_.func(); 1372 1373 // Create a function mirror. NOTE: MakeMirror cannot be used here as the 1374 // value returned from the VM might be a string if the function for the 1375 // frame is unresolved. 1376 if (IS_FUNCTION(f)) { 1377 return MakeMirror(f); 1378 } else { 1379 return new UnresolvedFunctionMirror(f); 1380 } 1381}; 1382 1383 1384FrameMirror.prototype.receiver = function() { 1385 return MakeMirror(this.details_.receiver()); 1386}; 1387 1388 1389FrameMirror.prototype.isConstructCall = function() { 1390 return this.details_.isConstructCall(); 1391}; 1392 1393 1394FrameMirror.prototype.isDebuggerFrame = function() { 1395 return this.details_.isDebuggerFrame(); 1396}; 1397 1398 1399FrameMirror.prototype.argumentCount = function() { 1400 return this.details_.argumentCount(); 1401}; 1402 1403 1404FrameMirror.prototype.argumentName = function(index) { 1405 return this.details_.argumentName(index); 1406}; 1407 1408 1409FrameMirror.prototype.argumentValue = function(index) { 1410 return MakeMirror(this.details_.argumentValue(index)); 1411}; 1412 1413 1414FrameMirror.prototype.localCount = function() { 1415 return this.details_.localCount(); 1416}; 1417 1418 1419FrameMirror.prototype.localName = function(index) { 1420 return this.details_.localName(index); 1421}; 1422 1423 1424FrameMirror.prototype.localValue = function(index) { 1425 return MakeMirror(this.details_.localValue(index)); 1426}; 1427 1428 1429FrameMirror.prototype.sourcePosition = function() { 1430 return this.details_.sourcePosition(); 1431}; 1432 1433 1434FrameMirror.prototype.sourceLocation = function() { 1435 if (this.func().resolved() && this.func().script()) { 1436 return this.func().script().locationFromPosition(this.sourcePosition(), 1437 true); 1438 } 1439}; 1440 1441 1442FrameMirror.prototype.sourceLine = function() { 1443 if (this.func().resolved()) { 1444 var location = this.sourceLocation(); 1445 if (location) { 1446 return location.line; 1447 } 1448 } 1449}; 1450 1451 1452FrameMirror.prototype.sourceColumn = function() { 1453 if (this.func().resolved()) { 1454 var location = this.sourceLocation(); 1455 if (location) { 1456 return location.column; 1457 } 1458 } 1459}; 1460 1461 1462FrameMirror.prototype.sourceLineText = function() { 1463 if (this.func().resolved()) { 1464 var location = this.sourceLocation(); 1465 if (location) { 1466 return location.sourceText(); 1467 } 1468 } 1469}; 1470 1471 1472FrameMirror.prototype.scopeCount = function() { 1473 return this.details_.scopeCount(); 1474}; 1475 1476 1477FrameMirror.prototype.scope = function(index) { 1478 return new ScopeMirror(this, index); 1479}; 1480 1481 1482FrameMirror.prototype.evaluate = function(source, disable_break) { 1483 var result = %DebugEvaluate(this.break_id_, this.details_.frameId(), 1484 source, Boolean(disable_break)); 1485 return MakeMirror(result); 1486}; 1487 1488 1489FrameMirror.prototype.invocationText = function() { 1490 // Format frame invoaction (receiver, function and arguments). 1491 var result = ''; 1492 var func = this.func(); 1493 var receiver = this.receiver(); 1494 if (this.isConstructCall()) { 1495 // For constructor frames display new followed by the function name. 1496 result += 'new '; 1497 result += func.name() ? func.name() : '[anonymous]'; 1498 } else if (this.isDebuggerFrame()) { 1499 result += '[debugger]'; 1500 } else { 1501 // If the receiver has a className which is 'global' don't display it. 1502 var display_receiver = !receiver.className || receiver.className() != 'global'; 1503 if (display_receiver) { 1504 result += receiver.toText(); 1505 } 1506 // Try to find the function as a property in the receiver. Include the 1507 // prototype chain in the lookup. 1508 var property = GetUndefinedMirror(); 1509 if (!receiver.isUndefined()) { 1510 for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) { 1511 property = r.lookupProperty(func); 1512 } 1513 } 1514 if (!property.isUndefined()) { 1515 // The function invoked was found on the receiver. Use the property name 1516 // for the backtrace. 1517 if (!property.isIndexed()) { 1518 if (display_receiver) { 1519 result += '.'; 1520 } 1521 result += property.name(); 1522 } else { 1523 result += '['; 1524 result += property.name(); 1525 result += ']'; 1526 } 1527 // Also known as - if the name in the function doesn't match the name 1528 // under which it was looked up. 1529 if (func.name() && func.name() != property.name()) { 1530 result += '(aka ' + func.name() + ')'; 1531 } 1532 } else { 1533 // The function invoked was not found on the receiver. Use the function 1534 // name if available for the backtrace. 1535 if (display_receiver) { 1536 result += '.'; 1537 } 1538 result += func.name() ? func.name() : '[anonymous]'; 1539 } 1540 } 1541 1542 // Render arguments for normal frames. 1543 if (!this.isDebuggerFrame()) { 1544 result += '('; 1545 for (var i = 0; i < this.argumentCount(); i++) { 1546 if (i != 0) result += ', '; 1547 if (this.argumentName(i)) { 1548 result += this.argumentName(i); 1549 result += '='; 1550 } 1551 result += this.argumentValue(i).toText(); 1552 } 1553 result += ')'; 1554 } 1555 1556 return result; 1557} 1558 1559 1560FrameMirror.prototype.sourceAndPositionText = function() { 1561 // Format source and position. 1562 var result = ''; 1563 var func = this.func(); 1564 if (func.resolved()) { 1565 if (func.script()) { 1566 if (func.script().name()) { 1567 result += func.script().name(); 1568 } else { 1569 result += '[unnamed]'; 1570 } 1571 if (!this.isDebuggerFrame()) { 1572 var location = this.sourceLocation(); 1573 result += ' line '; 1574 result += !IS_UNDEFINED(location) ? (location.line + 1) : '?'; 1575 result += ' column '; 1576 result += !IS_UNDEFINED(location) ? (location.column + 1) : '?'; 1577 if (!IS_UNDEFINED(this.sourcePosition())) { 1578 result += ' (position ' + (this.sourcePosition() + 1) + ')'; 1579 } 1580 } 1581 } else { 1582 result += '[no source]'; 1583 } 1584 } else { 1585 result += '[unresolved]'; 1586 } 1587 1588 return result; 1589} 1590 1591 1592FrameMirror.prototype.localsText = function() { 1593 // Format local variables. 1594 var result = ''; 1595 var locals_count = this.localCount() 1596 if (locals_count > 0) { 1597 for (var i = 0; i < locals_count; ++i) { 1598 result += ' var '; 1599 result += this.localName(i); 1600 result += ' = '; 1601 result += this.localValue(i).toText(); 1602 if (i < locals_count - 1) result += '\n'; 1603 } 1604 } 1605 1606 return result; 1607} 1608 1609 1610FrameMirror.prototype.toText = function(opt_locals) { 1611 var result = ''; 1612 result += '#' + (this.index() <= 9 ? '0' : '') + this.index(); 1613 result += ' '; 1614 result += this.invocationText(); 1615 result += ' '; 1616 result += this.sourceAndPositionText(); 1617 if (opt_locals) { 1618 result += '\n'; 1619 result += this.localsText(); 1620 } 1621 return result; 1622} 1623 1624 1625const kScopeDetailsTypeIndex = 0; 1626const kScopeDetailsObjectIndex = 1; 1627 1628function ScopeDetails(frame, index) { 1629 this.break_id_ = frame.break_id_; 1630 this.details_ = %GetScopeDetails(frame.break_id_, 1631 frame.details_.frameId(), 1632 index); 1633} 1634 1635 1636ScopeDetails.prototype.type = function() { 1637 %CheckExecutionState(this.break_id_); 1638 return this.details_[kScopeDetailsTypeIndex]; 1639} 1640 1641 1642ScopeDetails.prototype.object = function() { 1643 %CheckExecutionState(this.break_id_); 1644 return this.details_[kScopeDetailsObjectIndex]; 1645} 1646 1647 1648/** 1649 * Mirror object for scope. 1650 * @param {FrameMirror} frame The frame this scope is a part of 1651 * @param {number} index The scope index in the frame 1652 * @constructor 1653 * @extends Mirror 1654 */ 1655function ScopeMirror(frame, index) { 1656 Mirror.call(this, SCOPE_TYPE); 1657 this.frame_index_ = frame.index_; 1658 this.scope_index_ = index; 1659 this.details_ = new ScopeDetails(frame, index); 1660} 1661inherits(ScopeMirror, Mirror); 1662 1663 1664ScopeMirror.prototype.frameIndex = function() { 1665 return this.frame_index_; 1666}; 1667 1668 1669ScopeMirror.prototype.scopeIndex = function() { 1670 return this.scope_index_; 1671}; 1672 1673 1674ScopeMirror.prototype.scopeType = function() { 1675 return this.details_.type(); 1676}; 1677 1678 1679ScopeMirror.prototype.scopeObject = function() { 1680 // For local and closure scopes create a transient mirror as these objects are 1681 // created on the fly materializing the local or closure scopes and 1682 // therefore will not preserve identity. 1683 var transient = this.scopeType() == ScopeType.Local || 1684 this.scopeType() == ScopeType.Closure; 1685 return MakeMirror(this.details_.object(), transient); 1686}; 1687 1688 1689/** 1690 * Mirror object for script source. 1691 * @param {Script} script The script object 1692 * @constructor 1693 * @extends Mirror 1694 */ 1695function ScriptMirror(script) { 1696 Mirror.call(this, SCRIPT_TYPE); 1697 this.script_ = script; 1698 this.context_ = new ContextMirror(script.context_data); 1699 this.allocateHandle_(); 1700} 1701inherits(ScriptMirror, Mirror); 1702 1703 1704ScriptMirror.prototype.value = function() { 1705 return this.script_; 1706}; 1707 1708 1709ScriptMirror.prototype.name = function() { 1710 return this.script_.name; 1711}; 1712 1713 1714ScriptMirror.prototype.id = function() { 1715 return this.script_.id; 1716}; 1717 1718 1719ScriptMirror.prototype.source = function() { 1720 return this.script_.source; 1721}; 1722 1723 1724ScriptMirror.prototype.lineOffset = function() { 1725 return this.script_.line_offset; 1726}; 1727 1728 1729ScriptMirror.prototype.columnOffset = function() { 1730 return this.script_.column_offset; 1731}; 1732 1733 1734ScriptMirror.prototype.data = function() { 1735 return this.script_.data; 1736}; 1737 1738 1739ScriptMirror.prototype.scriptType = function() { 1740 return this.script_.type; 1741}; 1742 1743 1744ScriptMirror.prototype.compilationType = function() { 1745 return this.script_.compilation_type; 1746}; 1747 1748 1749ScriptMirror.prototype.lineCount = function() { 1750 return this.script_.lineCount(); 1751}; 1752 1753 1754ScriptMirror.prototype.locationFromPosition = function( 1755 position, include_resource_offset) { 1756 return this.script_.locationFromPosition(position, include_resource_offset); 1757} 1758 1759 1760ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) { 1761 return this.script_.sourceSlice(opt_from_line, opt_to_line); 1762} 1763 1764 1765ScriptMirror.prototype.context = function() { 1766 return this.context_; 1767}; 1768 1769 1770ScriptMirror.prototype.evalFromFunction = function() { 1771 return MakeMirror(this.script_.eval_from_function); 1772}; 1773 1774 1775ScriptMirror.prototype.evalFromLocation = function() { 1776 var eval_from_function = this.evalFromFunction(); 1777 if (!eval_from_function.isUndefined()) { 1778 var position = this.script_.eval_from_position; 1779 return eval_from_function.script().locationFromPosition(position, true); 1780 } 1781}; 1782 1783 1784ScriptMirror.prototype.toText = function() { 1785 var result = ''; 1786 result += this.name(); 1787 result += ' (lines: '; 1788 if (this.lineOffset() > 0) { 1789 result += this.lineOffset(); 1790 result += '-'; 1791 result += this.lineOffset() + this.lineCount() - 1; 1792 } else { 1793 result += this.lineCount(); 1794 } 1795 result += ')'; 1796 return result; 1797} 1798 1799 1800/** 1801 * Mirror object for context. 1802 * @param {Object} data The context data 1803 * @constructor 1804 * @extends Mirror 1805 */ 1806function ContextMirror(data) { 1807 Mirror.call(this, CONTEXT_TYPE); 1808 this.data_ = data; 1809 this.allocateHandle_(); 1810} 1811inherits(ContextMirror, Mirror); 1812 1813 1814ContextMirror.prototype.data = function() { 1815 return this.data_; 1816}; 1817 1818 1819/** 1820 * Returns a mirror serializer 1821 * 1822 * @param {boolean} details Set to true to include details 1823 * @param {Object} options Options comtrolling the serialization 1824 * The following options can be set: 1825 * includeSource: include ths full source of scripts 1826 * @returns {MirrorSerializer} mirror serializer 1827 */ 1828function MakeMirrorSerializer(details, options) { 1829 return new JSONProtocolSerializer(details, options); 1830} 1831 1832 1833/** 1834 * Object for serializing a mirror objects and its direct references. 1835 * @param {boolean} details Indicates whether to include details for the mirror 1836 * serialized 1837 * @constructor 1838 */ 1839function JSONProtocolSerializer(details, options) { 1840 this.details_ = details; 1841 this.options_ = options; 1842 this.mirrors_ = [ ]; 1843} 1844 1845 1846/** 1847 * Returns a serialization of an object reference. The referenced object are 1848 * added to the serialization state. 1849 * 1850 * @param {Mirror} mirror The mirror to serialize 1851 * @returns {String} JSON serialization 1852 */ 1853JSONProtocolSerializer.prototype.serializeReference = function(mirror) { 1854 return this.serialize_(mirror, true, true); 1855} 1856 1857 1858/** 1859 * Returns a serialization of an object value. The referenced objects are 1860 * added to the serialization state. 1861 * 1862 * @param {Mirror} mirror The mirror to serialize 1863 * @returns {String} JSON serialization 1864 */ 1865JSONProtocolSerializer.prototype.serializeValue = function(mirror) { 1866 var json = this.serialize_(mirror, false, true); 1867 return json; 1868} 1869 1870 1871/** 1872 * Returns a serialization of all the objects referenced. 1873 * 1874 * @param {Mirror} mirror The mirror to serialize. 1875 * @returns {Array.<Object>} Array of the referenced objects converted to 1876 * protcol objects. 1877 */ 1878JSONProtocolSerializer.prototype.serializeReferencedObjects = function() { 1879 // Collect the protocol representation of the referenced objects in an array. 1880 var content = []; 1881 1882 // Get the number of referenced objects. 1883 var count = this.mirrors_.length; 1884 1885 for (var i = 0; i < count; i++) { 1886 content.push(this.serialize_(this.mirrors_[i], false, false)); 1887 } 1888 1889 return content; 1890} 1891 1892 1893JSONProtocolSerializer.prototype.includeSource_ = function() { 1894 return this.options_ && this.options_.includeSource; 1895} 1896 1897 1898JSONProtocolSerializer.prototype.inlineRefs_ = function() { 1899 return this.options_ && this.options_.inlineRefs; 1900} 1901 1902 1903JSONProtocolSerializer.prototype.add_ = function(mirror) { 1904 // If this mirror is already in the list just return. 1905 for (var i = 0; i < this.mirrors_.length; i++) { 1906 if (this.mirrors_[i] === mirror) { 1907 return; 1908 } 1909 } 1910 1911 // Add the mirror to the list of mirrors to be serialized. 1912 this.mirrors_.push(mirror); 1913} 1914 1915 1916/** 1917 * Formats mirror object to protocol reference object with some data that can 1918 * be used to display the value in debugger. 1919 * @param {Mirror} mirror Mirror to serialize. 1920 * @return {Object} Protocol reference object. 1921 */ 1922JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ = 1923 function(mirror) { 1924 var o = {}; 1925 o.ref = mirror.handle(); 1926 o.type = mirror.type(); 1927 switch (mirror.type()) { 1928 case UNDEFINED_TYPE: 1929 case NULL_TYPE: 1930 case BOOLEAN_TYPE: 1931 case NUMBER_TYPE: 1932 o.value = mirror.value(); 1933 break; 1934 case STRING_TYPE: 1935 // Limit string length. 1936 o.value = mirror.toText(); 1937 break; 1938 case FUNCTION_TYPE: 1939 o.name = mirror.name(); 1940 o.inferredName = mirror.inferredName(); 1941 if (mirror.script()) { 1942 o.scriptId = mirror.script().id(); 1943 } 1944 break; 1945 case ERROR_TYPE: 1946 case REGEXP_TYPE: 1947 o.value = mirror.toText(); 1948 break; 1949 case OBJECT_TYPE: 1950 o.className = mirror.className(); 1951 break; 1952 } 1953 return o; 1954}; 1955 1956 1957JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, 1958 details) { 1959 // If serializing a reference to a mirror just return the reference and add 1960 // the mirror to the referenced mirrors. 1961 if (reference && 1962 (mirror.isValue() || mirror.isScript() || mirror.isContext())) { 1963 if (this.inlineRefs_() && mirror.isValue()) { 1964 return this.serializeReferenceWithDisplayData_(mirror); 1965 } else { 1966 this.add_(mirror); 1967 return {'ref' : mirror.handle()}; 1968 } 1969 } 1970 1971 // Collect the JSON property/value pairs. 1972 var content = {}; 1973 1974 // Add the mirror handle. 1975 if (mirror.isValue() || mirror.isScript() || mirror.isContext()) { 1976 content.handle = mirror.handle(); 1977 } 1978 1979 // Always add the type. 1980 content.type = mirror.type(); 1981 1982 switch (mirror.type()) { 1983 case UNDEFINED_TYPE: 1984 case NULL_TYPE: 1985 // Undefined and null are represented just by their type. 1986 break; 1987 1988 case BOOLEAN_TYPE: 1989 // Boolean values are simply represented by their value. 1990 content.value = mirror.value(); 1991 break; 1992 1993 case NUMBER_TYPE: 1994 // Number values are simply represented by their value. 1995 content.value = NumberToJSON_(mirror.value()); 1996 break; 1997 1998 case STRING_TYPE: 1999 // String values might have their value cropped to keep down size. 2000 if (mirror.length() > kMaxProtocolStringLength) { 2001 var str = mirror.value().substring(0, kMaxProtocolStringLength); 2002 content.value = str; 2003 content.fromIndex = 0; 2004 content.toIndex = kMaxProtocolStringLength; 2005 } else { 2006 content.value = mirror.value(); 2007 } 2008 content.length = mirror.length(); 2009 break; 2010 2011 case OBJECT_TYPE: 2012 case FUNCTION_TYPE: 2013 case ERROR_TYPE: 2014 case REGEXP_TYPE: 2015 // Add object representation. 2016 this.serializeObject_(mirror, content, details); 2017 break; 2018 2019 case PROPERTY_TYPE: 2020 throw new Error('PropertyMirror cannot be serialized independeltly') 2021 break; 2022 2023 case FRAME_TYPE: 2024 // Add object representation. 2025 this.serializeFrame_(mirror, content); 2026 break; 2027 2028 case SCOPE_TYPE: 2029 // Add object representation. 2030 this.serializeScope_(mirror, content); 2031 break; 2032 2033 case SCRIPT_TYPE: 2034 // Script is represented by id, name and source attributes. 2035 if (mirror.name()) { 2036 content.name = mirror.name(); 2037 } 2038 content.id = mirror.id(); 2039 content.lineOffset = mirror.lineOffset(); 2040 content.columnOffset = mirror.columnOffset(); 2041 content.lineCount = mirror.lineCount(); 2042 if (mirror.data()) { 2043 content.data = mirror.data(); 2044 } 2045 if (this.includeSource_()) { 2046 content.source = mirror.source(); 2047 } else { 2048 var sourceStart = mirror.source().substring(0, 80); 2049 content.sourceStart = sourceStart; 2050 } 2051 content.sourceLength = mirror.source().length; 2052 content.scriptType = mirror.scriptType(); 2053 content.compilationType = mirror.compilationType(); 2054 // For compilation type eval emit information on the script from which 2055 // eval was called if a script is present. 2056 if (mirror.compilationType() == 1 && 2057 mirror.evalFromFunction().script()) { 2058 content.evalFromScript = 2059 this.serializeReference(mirror.evalFromFunction().script()); 2060 var evalFromLocation = mirror.evalFromLocation() 2061 content.evalFromLocation = { line: evalFromLocation.line, 2062 column: evalFromLocation.column} 2063 } 2064 if (mirror.context()) { 2065 content.context = this.serializeReference(mirror.context()); 2066 } 2067 break; 2068 2069 case CONTEXT_TYPE: 2070 content.data = mirror.data(); 2071 break; 2072 } 2073 2074 // Always add the text representation. 2075 content.text = mirror.toText(); 2076 2077 // Create and return the JSON string. 2078 return content; 2079} 2080 2081 2082/** 2083 * Serialize object information to the following JSON format. 2084 * 2085 * {"className":"<class name>", 2086 * "constructorFunction":{"ref":<number>}, 2087 * "protoObject":{"ref":<number>}, 2088 * "prototypeObject":{"ref":<number>}, 2089 * "namedInterceptor":<boolean>, 2090 * "indexedInterceptor":<boolean>, 2091 * "properties":[<properties>]} 2092 */ 2093JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, 2094 details) { 2095 // Add general object properties. 2096 content.className = mirror.className(); 2097 content.constructorFunction = 2098 this.serializeReference(mirror.constructorFunction()); 2099 content.protoObject = this.serializeReference(mirror.protoObject()); 2100 content.prototypeObject = this.serializeReference(mirror.prototypeObject()); 2101 2102 // Add flags to indicate whether there are interceptors. 2103 if (mirror.hasNamedInterceptor()) { 2104 content.namedInterceptor = true; 2105 } 2106 if (mirror.hasIndexedInterceptor()) { 2107 content.indexedInterceptor = true; 2108 } 2109 2110 // Add function specific properties. 2111 if (mirror.isFunction()) { 2112 // Add function specific properties. 2113 content.name = mirror.name(); 2114 if (!IS_UNDEFINED(mirror.inferredName())) { 2115 content.inferredName = mirror.inferredName(); 2116 } 2117 content.resolved = mirror.resolved(); 2118 if (mirror.resolved()) { 2119 content.source = mirror.source(); 2120 } 2121 if (mirror.script()) { 2122 content.script = this.serializeReference(mirror.script()); 2123 } 2124 } 2125 2126 // Add date specific properties. 2127 if (mirror.isDate()) { 2128 // Add date specific properties. 2129 content.value = mirror.value(); 2130 } 2131 2132 // Add actual properties - named properties followed by indexed properties. 2133 var propertyNames = mirror.propertyNames(PropertyKind.Named); 2134 var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed); 2135 var p = new Array(propertyNames.length + propertyIndexes.length); 2136 for (var i = 0; i < propertyNames.length; i++) { 2137 var propertyMirror = mirror.property(propertyNames[i]); 2138 p[i] = this.serializeProperty_(propertyMirror); 2139 if (details) { 2140 this.add_(propertyMirror.value()); 2141 } 2142 } 2143 for (var i = 0; i < propertyIndexes.length; i++) { 2144 var propertyMirror = mirror.property(propertyIndexes[i]); 2145 p[propertyNames.length + i] = this.serializeProperty_(propertyMirror); 2146 if (details) { 2147 this.add_(propertyMirror.value()); 2148 } 2149 } 2150 content.properties = p; 2151} 2152 2153 2154/** 2155 * Serialize property information to the following JSON format for building the 2156 * array of properties. 2157 * 2158 * {"name":"<property name>", 2159 * "attributes":<number>, 2160 * "propertyType":<number>, 2161 * "ref":<number>} 2162 * 2163 * If the attribute for the property is PropertyAttribute.None it is not added. 2164 * If the propertyType for the property is PropertyType.Normal it is not added. 2165 * Here are a couple of examples. 2166 * 2167 * {"name":"hello","ref":1} 2168 * {"name":"length","attributes":7,"propertyType":3,"ref":2} 2169 * 2170 * @param {PropertyMirror} propertyMirror The property to serialize. 2171 * @returns {Object} Protocol object representing the property. 2172 */ 2173JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) { 2174 var result = {}; 2175 2176 result.name = propertyMirror.name(); 2177 var propertyValue = propertyMirror.value(); 2178 if (this.inlineRefs_() && propertyValue.isValue()) { 2179 result.value = this.serializeReferenceWithDisplayData_(propertyValue); 2180 } else { 2181 if (propertyMirror.attributes() != PropertyAttribute.None) { 2182 result.attributes = propertyMirror.attributes(); 2183 } 2184 if (propertyMirror.propertyType() != PropertyType.Normal) { 2185 result.propertyType = propertyMirror.propertyType(); 2186 } 2187 result.ref = propertyValue.handle(); 2188 } 2189 return result; 2190} 2191 2192 2193JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) { 2194 content.index = mirror.index(); 2195 content.receiver = this.serializeReference(mirror.receiver()); 2196 var func = mirror.func(); 2197 content.func = this.serializeReference(func); 2198 if (func.script()) { 2199 content.script = this.serializeReference(func.script()); 2200 } 2201 content.constructCall = mirror.isConstructCall(); 2202 content.debuggerFrame = mirror.isDebuggerFrame(); 2203 var x = new Array(mirror.argumentCount()); 2204 for (var i = 0; i < mirror.argumentCount(); i++) { 2205 var arg = {}; 2206 var argument_name = mirror.argumentName(i) 2207 if (argument_name) { 2208 arg.name = argument_name; 2209 } 2210 arg.value = this.serializeReference(mirror.argumentValue(i)); 2211 x[i] = arg; 2212 } 2213 content.arguments = x; 2214 var x = new Array(mirror.localCount()); 2215 for (var i = 0; i < mirror.localCount(); i++) { 2216 var local = {}; 2217 local.name = mirror.localName(i); 2218 local.value = this.serializeReference(mirror.localValue(i)); 2219 x[i] = local; 2220 } 2221 content.locals = x; 2222 content.position = mirror.sourcePosition(); 2223 var line = mirror.sourceLine(); 2224 if (!IS_UNDEFINED(line)) { 2225 content.line = line; 2226 } 2227 var column = mirror.sourceColumn(); 2228 if (!IS_UNDEFINED(column)) { 2229 content.column = column; 2230 } 2231 var source_line_text = mirror.sourceLineText(); 2232 if (!IS_UNDEFINED(source_line_text)) { 2233 content.sourceLineText = source_line_text; 2234 } 2235 2236 content.scopes = []; 2237 for (var i = 0; i < mirror.scopeCount(); i++) { 2238 var scope = mirror.scope(i); 2239 content.scopes.push({ 2240 type: scope.scopeType(), 2241 index: i 2242 }); 2243 } 2244} 2245 2246 2247JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) { 2248 content.index = mirror.scopeIndex(); 2249 content.frameIndex = mirror.frameIndex(); 2250 content.type = mirror.scopeType(); 2251 content.object = this.inlineRefs_() ? 2252 this.serializeValue(mirror.scopeObject()) : 2253 this.serializeReference(mirror.scopeObject()); 2254} 2255 2256 2257/** 2258 * Convert a number to a protocol value. For all finite numbers the number 2259 * itself is returned. For non finite numbers NaN, Infinite and 2260 * -Infinite the string representation "NaN", "Infinite" or "-Infinite" 2261 * (not including the quotes) is returned. 2262 * 2263 * @param {number} value The number value to convert to a protocol value. 2264 * @returns {number|string} Protocol value. 2265 */ 2266function NumberToJSON_(value) { 2267 if (isNaN(value)) { 2268 return 'NaN'; 2269 } 2270 if (!isFinite(value)) { 2271 if (value > 0) { 2272 return 'Infinity'; 2273 } else { 2274 return '-Infinity'; 2275 } 2276 } 2277 return value; 2278} 2279