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