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