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