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