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