mirrors.js revision bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8
1// Copyright 2006-2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5(function(global, utils) { 6"use strict"; 7 8// ---------------------------------------------------------------------------- 9// Imports 10 11var ErrorToString; 12var GlobalArray = global.Array; 13var IsNaN = global.isNaN; 14var JSONStringify = global.JSON.stringify; 15var MakeError; 16var MapEntries; 17var MapIteratorNext; 18var MathMin = global.Math.min; 19var promiseStateSymbol = utils.ImportNow("promise_state_symbol"); 20var promiseResultSymbol = utils.ImportNow("promise_result_symbol"); 21var SetIteratorNext; 22var SetValues; 23var SymbolToString; 24 25utils.Import(function(from) { 26 ErrorToString = from.ErrorToString; 27 MakeError = from.MakeError; 28 MapEntries = from.MapEntries; 29 MapIteratorNext = from.MapIteratorNext; 30 SetIteratorNext = from.SetIteratorNext; 31 SetValues = from.SetValues; 32 SymbolToString = from.SymbolToString; 33}); 34 35// ---------------------------------------------------------------------------- 36 37// Mirror hierarchy: 38// - Mirror 39// - ValueMirror 40// - UndefinedMirror 41// - NullMirror 42// - BooleanMirror 43// - NumberMirror 44// - StringMirror 45// - SymbolMirror 46// - ObjectMirror 47// - FunctionMirror 48// - UnresolvedFunctionMirror 49// - ArrayMirror 50// - DateMirror 51// - RegExpMirror 52// - ErrorMirror 53// - PromiseMirror 54// - MapMirror 55// - SetMirror 56// - IteratorMirror 57// - GeneratorMirror 58// - PropertyMirror 59// - InternalPropertyMirror 60// - FrameMirror 61// - ScriptMirror 62// - ScopeMirror 63 64// Type names of the different mirrors. 65var MirrorType = { 66 UNDEFINED_TYPE : 'undefined', 67 NULL_TYPE : 'null', 68 BOOLEAN_TYPE : 'boolean', 69 NUMBER_TYPE : 'number', 70 STRING_TYPE : 'string', 71 SYMBOL_TYPE : 'symbol', 72 OBJECT_TYPE : 'object', 73 FUNCTION_TYPE : 'function', 74 REGEXP_TYPE : 'regexp', 75 ERROR_TYPE : 'error', 76 PROPERTY_TYPE : 'property', 77 INTERNAL_PROPERTY_TYPE : 'internalProperty', 78 FRAME_TYPE : 'frame', 79 SCRIPT_TYPE : 'script', 80 CONTEXT_TYPE : 'context', 81 SCOPE_TYPE : 'scope', 82 PROMISE_TYPE : 'promise', 83 MAP_TYPE : 'map', 84 SET_TYPE : 'set', 85 ITERATOR_TYPE : 'iterator', 86 GENERATOR_TYPE : 'generator', 87} 88 89 90// Handle id counters. 91var next_handle_ = 0; 92var next_transient_handle_ = -1; 93 94// Mirror cache. 95var mirror_cache_ = []; 96var mirror_cache_enabled_ = true; 97 98 99function MirrorCacheIsEmpty() { 100 return next_handle_ == 0 && mirror_cache_.length == 0; 101} 102 103 104function ToggleMirrorCache(value) { 105 mirror_cache_enabled_ = value; 106 ClearMirrorCache(); 107} 108 109 110function ClearMirrorCache(value) { 111 next_handle_ = 0; 112 mirror_cache_ = []; 113} 114 115 116function ObjectIsPromise(value) { 117 return IS_RECEIVER(value) && 118 !IS_UNDEFINED(%DebugGetProperty(value, promiseStateSymbol)); 119} 120 121 122/** 123 * Returns the mirror for a specified value or object. 124 * 125 * @param {value or Object} value the value or object to retreive the mirror for 126 * @param {boolean} transient indicate whether this object is transient and 127 * should not be added to the mirror cache. The default is not transient. 128 * @returns {Mirror} the mirror reflects the passed value or object 129 */ 130function MakeMirror(value, opt_transient) { 131 var mirror; 132 133 // Look for non transient mirrors in the mirror cache. 134 if (!opt_transient && mirror_cache_enabled_) { 135 for (var id in mirror_cache_) { 136 mirror = mirror_cache_[id]; 137 if (mirror.value() === value) { 138 return mirror; 139 } 140 // Special check for NaN as NaN == NaN is false. 141 if (mirror.isNumber() && IsNaN(mirror.value()) && 142 typeof value == 'number' && IsNaN(value)) { 143 return mirror; 144 } 145 } 146 } 147 148 if (IS_UNDEFINED(value)) { 149 mirror = new UndefinedMirror(); 150 } else if (IS_NULL(value)) { 151 mirror = new NullMirror(); 152 } else if (IS_BOOLEAN(value)) { 153 mirror = new BooleanMirror(value); 154 } else if (IS_NUMBER(value)) { 155 mirror = new NumberMirror(value); 156 } else if (IS_STRING(value)) { 157 mirror = new StringMirror(value); 158 } else if (IS_SYMBOL(value)) { 159 mirror = new SymbolMirror(value); 160 } else if (IS_ARRAY(value)) { 161 mirror = new ArrayMirror(value); 162 } else if (IS_DATE(value)) { 163 mirror = new DateMirror(value); 164 } else if (IS_FUNCTION(value)) { 165 mirror = new FunctionMirror(value); 166 } else if (IS_REGEXP(value)) { 167 mirror = new RegExpMirror(value); 168 } else if (IS_ERROR(value)) { 169 mirror = new ErrorMirror(value); 170 } else if (IS_SCRIPT(value)) { 171 mirror = new ScriptMirror(value); 172 } else if (IS_MAP(value) || IS_WEAKMAP(value)) { 173 mirror = new MapMirror(value); 174 } else if (IS_SET(value) || IS_WEAKSET(value)) { 175 mirror = new SetMirror(value); 176 } else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) { 177 mirror = new IteratorMirror(value); 178 } else if (ObjectIsPromise(value)) { 179 mirror = new PromiseMirror(value); 180 } else if (IS_GENERATOR(value)) { 181 mirror = new GeneratorMirror(value); 182 } else { 183 mirror = new ObjectMirror(value, MirrorType.OBJECT_TYPE, opt_transient); 184 } 185 186 if (mirror_cache_enabled_) mirror_cache_[mirror.handle()] = mirror; 187 return mirror; 188} 189 190 191/** 192 * Returns the mirror for a specified mirror handle. 193 * 194 * @param {number} handle the handle to find the mirror for 195 * @returns {Mirror or undefiend} the mirror with the requested handle or 196 * undefined if no mirror with the requested handle was found 197 */ 198function LookupMirror(handle) { 199 if (!mirror_cache_enabled_) { 200 throw MakeError(kDebugger, "Mirror cache is disabled"); 201 } 202 return mirror_cache_[handle]; 203} 204 205 206/** 207 * Returns the mirror for the undefined value. 208 * 209 * @returns {Mirror} the mirror reflects the undefined value 210 */ 211function GetUndefinedMirror() { 212 return MakeMirror(UNDEFINED); 213} 214 215 216/** 217 * Inherit the prototype methods from one constructor into another. 218 * 219 * The Function.prototype.inherits from lang.js rewritten as a standalone 220 * function (not on Function.prototype). NOTE: If this file is to be loaded 221 * during bootstrapping this function needs to be revritten using some native 222 * functions as prototype setup using normal JavaScript does not work as 223 * expected during bootstrapping (see mirror.js in r114903). 224 * 225 * @param {function} ctor Constructor function which needs to inherit the 226 * prototype 227 * @param {function} superCtor Constructor function to inherit prototype from 228 */ 229function inherits(ctor, superCtor) { 230 var tempCtor = function(){}; 231 tempCtor.prototype = superCtor.prototype; 232 ctor.super_ = superCtor.prototype; 233 ctor.prototype = new tempCtor(); 234 ctor.prototype.constructor = ctor; 235} 236 237// Maximum length when sending strings through the JSON protocol. 238var kMaxProtocolStringLength = 80; 239 240 241// A copy of the PropertyType enum from property-details.h 242var PropertyType = {}; 243PropertyType.Data = 0; 244PropertyType.DataConstant = 2; 245PropertyType.AccessorConstant = 3; 246 247 248// Different attributes for a property. 249var PropertyAttribute = {}; 250PropertyAttribute.None = NONE; 251PropertyAttribute.ReadOnly = READ_ONLY; 252PropertyAttribute.DontEnum = DONT_ENUM; 253PropertyAttribute.DontDelete = DONT_DELETE; 254 255 256// A copy of the scope types from runtime-debug.cc. 257// NOTE: these constants should be backward-compatible, so 258// add new ones to the end of this list. 259var ScopeType = { Global: 0, 260 Local: 1, 261 With: 2, 262 Closure: 3, 263 Catch: 4, 264 Block: 5, 265 Script: 6, 266 Eval: 7, 267 }; 268 269/** 270 * Base class for all mirror objects. 271 * @param {string} type The type of the mirror 272 * @constructor 273 */ 274function Mirror(type) { 275 this.type_ = type; 276} 277 278 279Mirror.prototype.type = function() { 280 return this.type_; 281}; 282 283 284/** 285 * Check whether the mirror reflects a value. 286 * @returns {boolean} True if the mirror reflects a value. 287 */ 288Mirror.prototype.isValue = function() { 289 return this instanceof ValueMirror; 290}; 291 292 293/** 294 * Check whether the mirror reflects the undefined value. 295 * @returns {boolean} True if the mirror reflects the undefined value. 296 */ 297Mirror.prototype.isUndefined = function() { 298 return this instanceof UndefinedMirror; 299}; 300 301 302/** 303 * Check whether the mirror reflects the null value. 304 * @returns {boolean} True if the mirror reflects the null value 305 */ 306Mirror.prototype.isNull = function() { 307 return this instanceof NullMirror; 308}; 309 310 311/** 312 * Check whether the mirror reflects a boolean value. 313 * @returns {boolean} True if the mirror reflects a boolean value 314 */ 315Mirror.prototype.isBoolean = function() { 316 return this instanceof BooleanMirror; 317}; 318 319 320/** 321 * Check whether the mirror reflects a number value. 322 * @returns {boolean} True if the mirror reflects a number value 323 */ 324Mirror.prototype.isNumber = function() { 325 return this instanceof NumberMirror; 326}; 327 328 329/** 330 * Check whether the mirror reflects a string value. 331 * @returns {boolean} True if the mirror reflects a string value 332 */ 333Mirror.prototype.isString = function() { 334 return this instanceof StringMirror; 335}; 336 337 338/** 339 * Check whether the mirror reflects a symbol. 340 * @returns {boolean} True if the mirror reflects a symbol 341 */ 342Mirror.prototype.isSymbol = function() { 343 return this instanceof SymbolMirror; 344}; 345 346 347/** 348 * Check whether the mirror reflects an object. 349 * @returns {boolean} True if the mirror reflects an object 350 */ 351Mirror.prototype.isObject = function() { 352 return this instanceof ObjectMirror; 353}; 354 355 356/** 357 * Check whether the mirror reflects a function. 358 * @returns {boolean} True if the mirror reflects a function 359 */ 360Mirror.prototype.isFunction = function() { 361 return this instanceof FunctionMirror; 362}; 363 364 365/** 366 * Check whether the mirror reflects an unresolved function. 367 * @returns {boolean} True if the mirror reflects an unresolved function 368 */ 369Mirror.prototype.isUnresolvedFunction = function() { 370 return this instanceof UnresolvedFunctionMirror; 371}; 372 373 374/** 375 * Check whether the mirror reflects an array. 376 * @returns {boolean} True if the mirror reflects an array 377 */ 378Mirror.prototype.isArray = function() { 379 return this instanceof ArrayMirror; 380}; 381 382 383/** 384 * Check whether the mirror reflects a date. 385 * @returns {boolean} True if the mirror reflects a date 386 */ 387Mirror.prototype.isDate = function() { 388 return this instanceof DateMirror; 389}; 390 391 392/** 393 * Check whether the mirror reflects a regular expression. 394 * @returns {boolean} True if the mirror reflects a regular expression 395 */ 396Mirror.prototype.isRegExp = function() { 397 return this instanceof RegExpMirror; 398}; 399 400 401/** 402 * Check whether the mirror reflects an error. 403 * @returns {boolean} True if the mirror reflects an error 404 */ 405Mirror.prototype.isError = function() { 406 return this instanceof ErrorMirror; 407}; 408 409 410/** 411 * Check whether the mirror reflects a promise. 412 * @returns {boolean} True if the mirror reflects a promise 413 */ 414Mirror.prototype.isPromise = function() { 415 return this instanceof PromiseMirror; 416}; 417 418 419/** 420 * Check whether the mirror reflects a generator object. 421 * @returns {boolean} True if the mirror reflects a generator object 422 */ 423Mirror.prototype.isGenerator = function() { 424 return this instanceof GeneratorMirror; 425}; 426 427 428/** 429 * Check whether the mirror reflects a property. 430 * @returns {boolean} True if the mirror reflects a property 431 */ 432Mirror.prototype.isProperty = function() { 433 return this instanceof PropertyMirror; 434}; 435 436 437/** 438 * Check whether the mirror reflects an internal property. 439 * @returns {boolean} True if the mirror reflects an internal property 440 */ 441Mirror.prototype.isInternalProperty = function() { 442 return this instanceof InternalPropertyMirror; 443}; 444 445 446/** 447 * Check whether the mirror reflects a stack frame. 448 * @returns {boolean} True if the mirror reflects a stack frame 449 */ 450Mirror.prototype.isFrame = function() { 451 return this instanceof FrameMirror; 452}; 453 454 455/** 456 * Check whether the mirror reflects a script. 457 * @returns {boolean} True if the mirror reflects a script 458 */ 459Mirror.prototype.isScript = function() { 460 return this instanceof ScriptMirror; 461}; 462 463 464/** 465 * Check whether the mirror reflects a context. 466 * @returns {boolean} True if the mirror reflects a context 467 */ 468Mirror.prototype.isContext = function() { 469 return this instanceof ContextMirror; 470}; 471 472 473/** 474 * Check whether the mirror reflects a scope. 475 * @returns {boolean} True if the mirror reflects a scope 476 */ 477Mirror.prototype.isScope = function() { 478 return this instanceof ScopeMirror; 479}; 480 481 482/** 483 * Check whether the mirror reflects a map. 484 * @returns {boolean} True if the mirror reflects a map 485 */ 486Mirror.prototype.isMap = function() { 487 return this instanceof MapMirror; 488}; 489 490 491/** 492 * Check whether the mirror reflects a set. 493 * @returns {boolean} True if the mirror reflects a set 494 */ 495Mirror.prototype.isSet = function() { 496 return this instanceof SetMirror; 497}; 498 499 500/** 501 * Check whether the mirror reflects an iterator. 502 * @returns {boolean} True if the mirror reflects an iterator 503 */ 504Mirror.prototype.isIterator = function() { 505 return this instanceof IteratorMirror; 506}; 507 508 509/** 510 * Allocate a handle id for this object. 511 */ 512Mirror.prototype.allocateHandle_ = function() { 513 if (mirror_cache_enabled_) this.handle_ = next_handle_++; 514}; 515 516 517/** 518 * Allocate a transient handle id for this object. Transient handles are 519 * negative. 520 */ 521Mirror.prototype.allocateTransientHandle_ = function() { 522 this.handle_ = next_transient_handle_--; 523}; 524 525 526Mirror.prototype.toText = function() { 527 // Simpel to text which is used when on specialization in subclass. 528 return "#<" + this.constructor.name + ">"; 529}; 530 531 532/** 533 * Base class for all value mirror objects. 534 * @param {string} type The type of the mirror 535 * @param {value} value The value reflected by this mirror 536 * @param {boolean} transient indicate whether this object is transient with a 537 * transient handle 538 * @constructor 539 * @extends Mirror 540 */ 541function ValueMirror(type, value, transient) { 542 %_Call(Mirror, this, type); 543 this.value_ = value; 544 if (!transient) { 545 this.allocateHandle_(); 546 } else { 547 this.allocateTransientHandle_(); 548 } 549} 550inherits(ValueMirror, Mirror); 551 552 553Mirror.prototype.handle = function() { 554 return this.handle_; 555}; 556 557 558/** 559 * Check whether this is a primitive value. 560 * @return {boolean} True if the mirror reflects a primitive value 561 */ 562ValueMirror.prototype.isPrimitive = function() { 563 var type = this.type(); 564 return type === 'undefined' || 565 type === 'null' || 566 type === 'boolean' || 567 type === 'number' || 568 type === 'string' || 569 type === 'symbol'; 570}; 571 572 573/** 574 * Get the actual value reflected by this mirror. 575 * @return {value} The value reflected by this mirror 576 */ 577ValueMirror.prototype.value = function() { 578 return this.value_; 579}; 580 581 582/** 583 * Mirror object for Undefined. 584 * @constructor 585 * @extends ValueMirror 586 */ 587function UndefinedMirror() { 588 %_Call(ValueMirror, this, MirrorType.UNDEFINED_TYPE, UNDEFINED); 589} 590inherits(UndefinedMirror, ValueMirror); 591 592 593UndefinedMirror.prototype.toText = function() { 594 return 'undefined'; 595}; 596 597 598/** 599 * Mirror object for null. 600 * @constructor 601 * @extends ValueMirror 602 */ 603function NullMirror() { 604 %_Call(ValueMirror, this, MirrorType.NULL_TYPE, null); 605} 606inherits(NullMirror, ValueMirror); 607 608 609NullMirror.prototype.toText = function() { 610 return 'null'; 611}; 612 613 614/** 615 * Mirror object for boolean values. 616 * @param {boolean} value The boolean value reflected by this mirror 617 * @constructor 618 * @extends ValueMirror 619 */ 620function BooleanMirror(value) { 621 %_Call(ValueMirror, this, MirrorType.BOOLEAN_TYPE, value); 622} 623inherits(BooleanMirror, ValueMirror); 624 625 626BooleanMirror.prototype.toText = function() { 627 return this.value_ ? 'true' : 'false'; 628}; 629 630 631/** 632 * Mirror object for number values. 633 * @param {number} value The number value reflected by this mirror 634 * @constructor 635 * @extends ValueMirror 636 */ 637function NumberMirror(value) { 638 %_Call(ValueMirror, this, MirrorType.NUMBER_TYPE, value); 639} 640inherits(NumberMirror, ValueMirror); 641 642 643NumberMirror.prototype.toText = function() { 644 return %_NumberToString(this.value_); 645}; 646 647 648/** 649 * Mirror object for string values. 650 * @param {string} value The string value reflected by this mirror 651 * @constructor 652 * @extends ValueMirror 653 */ 654function StringMirror(value) { 655 %_Call(ValueMirror, this, MirrorType.STRING_TYPE, value); 656} 657inherits(StringMirror, ValueMirror); 658 659 660StringMirror.prototype.length = function() { 661 return this.value_.length; 662}; 663 664StringMirror.prototype.getTruncatedValue = function(maxLength) { 665 if (maxLength != -1 && this.length() > maxLength) { 666 return this.value_.substring(0, maxLength) + 667 '... (length: ' + this.length() + ')'; 668 } 669 return this.value_; 670}; 671 672StringMirror.prototype.toText = function() { 673 return this.getTruncatedValue(kMaxProtocolStringLength); 674}; 675 676 677/** 678 * Mirror object for a Symbol 679 * @param {Object} value The Symbol 680 * @constructor 681 * @extends Mirror 682 */ 683function SymbolMirror(value) { 684 %_Call(ValueMirror, this, MirrorType.SYMBOL_TYPE, value); 685} 686inherits(SymbolMirror, ValueMirror); 687 688 689SymbolMirror.prototype.description = function() { 690 return %SymbolDescription(%_ValueOf(this.value_)); 691} 692 693 694SymbolMirror.prototype.toText = function() { 695 return %_Call(SymbolToString, this.value_); 696} 697 698 699/** 700 * Mirror object for objects. 701 * @param {object} value The object reflected by this mirror 702 * @param {boolean} transient indicate whether this object is transient with a 703 * transient handle 704 * @constructor 705 * @extends ValueMirror 706 */ 707function ObjectMirror(value, type, transient) { 708 type = type || MirrorType.OBJECT_TYPE; 709 %_Call(ValueMirror, this, type, value, transient); 710} 711inherits(ObjectMirror, ValueMirror); 712 713 714ObjectMirror.prototype.className = function() { 715 return %_ClassOf(this.value_); 716}; 717 718 719ObjectMirror.prototype.constructorFunction = function() { 720 return MakeMirror(%DebugGetProperty(this.value_, 'constructor')); 721}; 722 723 724ObjectMirror.prototype.prototypeObject = function() { 725 return MakeMirror(%DebugGetProperty(this.value_, 'prototype')); 726}; 727 728 729ObjectMirror.prototype.protoObject = function() { 730 return MakeMirror(%DebugGetPrototype(this.value_)); 731}; 732 733 734ObjectMirror.prototype.hasNamedInterceptor = function() { 735 // Get information on interceptors for this object. 736 var x = %GetInterceptorInfo(this.value_); 737 return (x & 2) != 0; 738}; 739 740 741ObjectMirror.prototype.hasIndexedInterceptor = function() { 742 // Get information on interceptors for this object. 743 var x = %GetInterceptorInfo(this.value_); 744 return (x & 1) != 0; 745}; 746 747 748/** 749 * Return the property names for this object. 750 * @param {number} kind Indicate whether named, indexed or both kinds of 751 * properties are requested 752 * @param {number} limit Limit the number of names returend to the specified 753 value 754 * @return {Array} Property names for this object 755 */ 756ObjectMirror.prototype.propertyNames = function() { 757 return %GetOwnPropertyKeys(this.value_, PROPERTY_FILTER_NONE); 758}; 759 760 761/** 762 * Return the properties for this object as an array of PropertyMirror objects. 763 * @param {number} kind Indicate whether named, indexed or both kinds of 764 * properties are requested 765 * @param {number} limit Limit the number of properties returned to the 766 specified value 767 * @return {Array} Property mirrors for this object 768 */ 769ObjectMirror.prototype.properties = function() { 770 var names = this.propertyNames(); 771 var properties = new GlobalArray(names.length); 772 for (var i = 0; i < names.length; i++) { 773 properties[i] = this.property(names[i]); 774 } 775 776 return properties; 777}; 778 779 780/** 781 * Return the internal properties for this object as an array of 782 * InternalPropertyMirror objects. 783 * @return {Array} Property mirrors for this object 784 */ 785ObjectMirror.prototype.internalProperties = function() { 786 return ObjectMirror.GetInternalProperties(this.value_); 787} 788 789 790ObjectMirror.prototype.property = function(name) { 791 var details = %DebugGetPropertyDetails(this.value_, TO_NAME(name)); 792 if (details) { 793 return new PropertyMirror(this, name, details); 794 } 795 796 // Nothing found. 797 return GetUndefinedMirror(); 798}; 799 800 801 802/** 803 * Try to find a property from its value. 804 * @param {Mirror} value The property value to look for 805 * @return {PropertyMirror} The property with the specified value. If no 806 * property was found with the specified value UndefinedMirror is returned 807 */ 808ObjectMirror.prototype.lookupProperty = function(value) { 809 var properties = this.properties(); 810 811 // Look for property value in properties. 812 for (var i = 0; i < properties.length; i++) { 813 814 // Skip properties which are defined through accessors. 815 var property = properties[i]; 816 if (property.propertyType() != PropertyType.AccessorConstant) { 817 if (property.value_ === value.value_) { 818 return property; 819 } 820 } 821 } 822 823 // Nothing found. 824 return GetUndefinedMirror(); 825}; 826 827 828/** 829 * Returns objects which has direct references to this object 830 * @param {number} opt_max_objects Optional parameter specifying the maximum 831 * number of referencing objects to return. 832 * @return {Array} The objects which has direct references to this object. 833 */ 834ObjectMirror.prototype.referencedBy = function(opt_max_objects) { 835 // Find all objects with direct references to this object. 836 var result = %DebugReferencedBy(this.value_, 837 Mirror.prototype, opt_max_objects || 0); 838 839 // Make mirrors for all the references found. 840 for (var i = 0; i < result.length; i++) { 841 result[i] = MakeMirror(result[i]); 842 } 843 844 return result; 845}; 846 847 848ObjectMirror.prototype.toText = function() { 849 var name; 850 var ctor = this.constructorFunction(); 851 if (!ctor.isFunction()) { 852 name = this.className(); 853 } else { 854 name = ctor.name(); 855 if (!name) { 856 name = this.className(); 857 } 858 } 859 return '#<' + name + '>'; 860}; 861 862 863/** 864 * Return the internal properties of the value, such as [[PrimitiveValue]] of 865 * scalar wrapper objects, properties of the bound function and properties of 866 * the promise. 867 * This method is done static to be accessible from Debug API with the bare 868 * values without mirrors. 869 * @return {Array} array (possibly empty) of InternalProperty instances 870 */ 871ObjectMirror.GetInternalProperties = function(value) { 872 var properties = %DebugGetInternalProperties(value); 873 var result = []; 874 for (var i = 0; i < properties.length; i += 2) { 875 result.push(new InternalPropertyMirror(properties[i], properties[i + 1])); 876 } 877 return result; 878} 879 880 881/** 882 * Mirror object for functions. 883 * @param {function} value The function object reflected by this mirror. 884 * @constructor 885 * @extends ObjectMirror 886 */ 887function FunctionMirror(value) { 888 %_Call(ObjectMirror, this, value, MirrorType.FUNCTION_TYPE); 889 this.resolved_ = true; 890} 891inherits(FunctionMirror, ObjectMirror); 892 893 894/** 895 * Returns whether the function is resolved. 896 * @return {boolean} True if the function is resolved. Unresolved functions can 897 * only originate as functions from stack frames 898 */ 899FunctionMirror.prototype.resolved = function() { 900 return this.resolved_; 901}; 902 903 904/** 905 * Returns the name of the function. 906 * @return {string} Name of the function 907 */ 908FunctionMirror.prototype.name = function() { 909 return %FunctionGetName(this.value_); 910}; 911 912 913/** 914 * Returns the displayName if it is set, otherwise name, otherwise inferred 915 * name. 916 * @return {string} Name of the function 917 */ 918FunctionMirror.prototype.debugName = function() { 919 return %FunctionGetDebugName(this.value_); 920} 921 922 923/** 924 * Returns the inferred name of the function. 925 * @return {string} Name of the function 926 */ 927FunctionMirror.prototype.inferredName = function() { 928 return %FunctionGetInferredName(this.value_); 929}; 930 931 932/** 933 * Returns the source code for the function. 934 * @return {string or undefined} The source code for the function. If the 935 * function is not resolved undefined will be returned. 936 */ 937FunctionMirror.prototype.source = function() { 938 // Return source if function is resolved. Otherwise just fall through to 939 // return undefined. 940 if (this.resolved()) { 941 return %FunctionToString(this.value_); 942 } 943}; 944 945 946/** 947 * Returns the script object for the function. 948 * @return {ScriptMirror or undefined} Script object for the function or 949 * undefined if the function has no script 950 */ 951FunctionMirror.prototype.script = function() { 952 // Return script if function is resolved. Otherwise just fall through 953 // to return undefined. 954 if (this.resolved()) { 955 if (this.script_) { 956 return this.script_; 957 } 958 var script = %FunctionGetScript(this.value_); 959 if (script) { 960 return this.script_ = MakeMirror(script); 961 } 962 } 963}; 964 965 966/** 967 * Returns the script source position for the function. Only makes sense 968 * for functions which has a script defined. 969 * @return {Number or undefined} in-script position for the function 970 */ 971FunctionMirror.prototype.sourcePosition_ = function() { 972 // Return position if function is resolved. Otherwise just fall 973 // through to return undefined. 974 if (this.resolved()) { 975 return %FunctionGetScriptSourcePosition(this.value_); 976 } 977}; 978 979 980/** 981 * Returns the script source location object for the function. Only makes sense 982 * for functions which has a script defined. 983 * @return {Location or undefined} in-script location for the function begin 984 */ 985FunctionMirror.prototype.sourceLocation = function() { 986 if (this.resolved()) { 987 var script = this.script(); 988 if (script) { 989 return script.locationFromPosition(this.sourcePosition_(), true); 990 } 991 } 992}; 993 994 995/** 996 * Returns objects constructed by this function. 997 * @param {number} opt_max_instances Optional parameter specifying the maximum 998 * number of instances to return. 999 * @return {Array or undefined} The objects constructed by this function. 1000 */ 1001FunctionMirror.prototype.constructedBy = function(opt_max_instances) { 1002 if (this.resolved()) { 1003 // Find all objects constructed from this function. 1004 var result = %DebugConstructedBy(this.value_, opt_max_instances || 0); 1005 1006 // Make mirrors for all the instances found. 1007 for (var i = 0; i < result.length; i++) { 1008 result[i] = MakeMirror(result[i]); 1009 } 1010 1011 return result; 1012 } else { 1013 return []; 1014 } 1015}; 1016 1017 1018FunctionMirror.prototype.scopeCount = function() { 1019 if (this.resolved()) { 1020 if (IS_UNDEFINED(this.scopeCount_)) { 1021 this.scopeCount_ = %GetFunctionScopeCount(this.value()); 1022 } 1023 return this.scopeCount_; 1024 } else { 1025 return 0; 1026 } 1027}; 1028 1029 1030FunctionMirror.prototype.scope = function(index) { 1031 if (this.resolved()) { 1032 return new ScopeMirror(UNDEFINED, this, index); 1033 } 1034}; 1035 1036 1037FunctionMirror.prototype.toText = function() { 1038 return this.source(); 1039}; 1040 1041 1042FunctionMirror.prototype.context = function() { 1043 if (this.resolved()) { 1044 if (!this._context) 1045 this._context = new ContextMirror(%FunctionGetContextData(this.value_)); 1046 return this._context; 1047 } 1048}; 1049 1050 1051/** 1052 * Mirror object for unresolved functions. 1053 * @param {string} value The name for the unresolved function reflected by this 1054 * mirror. 1055 * @constructor 1056 * @extends ObjectMirror 1057 */ 1058function UnresolvedFunctionMirror(value) { 1059 // Construct this using the ValueMirror as an unresolved function is not a 1060 // real object but just a string. 1061 %_Call(ValueMirror, this, MirrorType.FUNCTION_TYPE, value); 1062 this.propertyCount_ = 0; 1063 this.elementCount_ = 0; 1064 this.resolved_ = false; 1065} 1066inherits(UnresolvedFunctionMirror, FunctionMirror); 1067 1068 1069UnresolvedFunctionMirror.prototype.className = function() { 1070 return 'Function'; 1071}; 1072 1073 1074UnresolvedFunctionMirror.prototype.constructorFunction = function() { 1075 return GetUndefinedMirror(); 1076}; 1077 1078 1079UnresolvedFunctionMirror.prototype.prototypeObject = function() { 1080 return GetUndefinedMirror(); 1081}; 1082 1083 1084UnresolvedFunctionMirror.prototype.protoObject = function() { 1085 return GetUndefinedMirror(); 1086}; 1087 1088 1089UnresolvedFunctionMirror.prototype.name = function() { 1090 return this.value_; 1091}; 1092 1093 1094UnresolvedFunctionMirror.prototype.inferredName = function() { 1095 return UNDEFINED; 1096}; 1097 1098 1099UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) { 1100 return []; 1101}; 1102 1103 1104/** 1105 * Mirror object for arrays. 1106 * @param {Array} value The Array object reflected by this mirror 1107 * @constructor 1108 * @extends ObjectMirror 1109 */ 1110function ArrayMirror(value) { 1111 %_Call(ObjectMirror, this, value); 1112} 1113inherits(ArrayMirror, ObjectMirror); 1114 1115 1116ArrayMirror.prototype.length = function() { 1117 return this.value_.length; 1118}; 1119 1120 1121ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, 1122 opt_to_index) { 1123 var from_index = opt_from_index || 0; 1124 var to_index = opt_to_index || this.length() - 1; 1125 if (from_index > to_index) return new GlobalArray(); 1126 var values = new GlobalArray(to_index - from_index + 1); 1127 for (var i = from_index; i <= to_index; i++) { 1128 var details = %DebugGetPropertyDetails(this.value_, TO_STRING(i)); 1129 var value; 1130 if (details) { 1131 value = new PropertyMirror(this, i, details); 1132 } else { 1133 value = GetUndefinedMirror(); 1134 } 1135 values[i - from_index] = value; 1136 } 1137 return values; 1138}; 1139 1140 1141/** 1142 * Mirror object for dates. 1143 * @param {Date} value The Date object reflected by this mirror 1144 * @constructor 1145 * @extends ObjectMirror 1146 */ 1147function DateMirror(value) { 1148 %_Call(ObjectMirror, this, value); 1149} 1150inherits(DateMirror, ObjectMirror); 1151 1152 1153DateMirror.prototype.toText = function() { 1154 var s = JSONStringify(this.value_); 1155 return s.substring(1, s.length - 1); // cut quotes 1156}; 1157 1158 1159/** 1160 * Mirror object for regular expressions. 1161 * @param {RegExp} value The RegExp object reflected by this mirror 1162 * @constructor 1163 * @extends ObjectMirror 1164 */ 1165function RegExpMirror(value) { 1166 %_Call(ObjectMirror, this, value, MirrorType.REGEXP_TYPE); 1167} 1168inherits(RegExpMirror, ObjectMirror); 1169 1170 1171/** 1172 * Returns the source to the regular expression. 1173 * @return {string or undefined} The source to the regular expression 1174 */ 1175RegExpMirror.prototype.source = function() { 1176 return this.value_.source; 1177}; 1178 1179 1180/** 1181 * Returns whether this regular expression has the global (g) flag set. 1182 * @return {boolean} Value of the global flag 1183 */ 1184RegExpMirror.prototype.global = function() { 1185 return this.value_.global; 1186}; 1187 1188 1189/** 1190 * Returns whether this regular expression has the ignore case (i) flag set. 1191 * @return {boolean} Value of the ignore case flag 1192 */ 1193RegExpMirror.prototype.ignoreCase = function() { 1194 return this.value_.ignoreCase; 1195}; 1196 1197 1198/** 1199 * Returns whether this regular expression has the multiline (m) flag set. 1200 * @return {boolean} Value of the multiline flag 1201 */ 1202RegExpMirror.prototype.multiline = function() { 1203 return this.value_.multiline; 1204}; 1205 1206 1207/** 1208 * Returns whether this regular expression has the sticky (y) flag set. 1209 * @return {boolean} Value of the sticky flag 1210 */ 1211RegExpMirror.prototype.sticky = function() { 1212 return this.value_.sticky; 1213}; 1214 1215 1216/** 1217 * Returns whether this regular expression has the unicode (u) flag set. 1218 * @return {boolean} Value of the unicode flag 1219 */ 1220RegExpMirror.prototype.unicode = function() { 1221 return this.value_.unicode; 1222}; 1223 1224 1225RegExpMirror.prototype.toText = function() { 1226 // Simpel to text which is used when on specialization in subclass. 1227 return "/" + this.source() + "/"; 1228}; 1229 1230 1231/** 1232 * Mirror object for error objects. 1233 * @param {Error} value The error object reflected by this mirror 1234 * @constructor 1235 * @extends ObjectMirror 1236 */ 1237function ErrorMirror(value) { 1238 %_Call(ObjectMirror, this, value, MirrorType.ERROR_TYPE); 1239} 1240inherits(ErrorMirror, ObjectMirror); 1241 1242 1243/** 1244 * Returns the message for this eror object. 1245 * @return {string or undefined} The message for this eror object 1246 */ 1247ErrorMirror.prototype.message = function() { 1248 return this.value_.message; 1249}; 1250 1251 1252ErrorMirror.prototype.toText = function() { 1253 // Use the same text representation as in messages.js. 1254 var text; 1255 try { 1256 text = %_Call(ErrorToString, this.value_); 1257 } catch (e) { 1258 text = '#<Error>'; 1259 } 1260 return text; 1261}; 1262 1263 1264/** 1265 * Mirror object for a Promise object. 1266 * @param {Object} value The Promise object 1267 * @constructor 1268 * @extends ObjectMirror 1269 */ 1270function PromiseMirror(value) { 1271 %_Call(ObjectMirror, this, value, MirrorType.PROMISE_TYPE); 1272} 1273inherits(PromiseMirror, ObjectMirror); 1274 1275 1276function PromiseGetStatus_(value) { 1277 var status = %DebugGetProperty(value, promiseStateSymbol); 1278 if (status == 0) return "pending"; 1279 if (status == 1) return "resolved"; 1280 return "rejected"; 1281} 1282 1283 1284function PromiseGetValue_(value) { 1285 return %DebugGetProperty(value, promiseResultSymbol); 1286} 1287 1288 1289PromiseMirror.prototype.status = function() { 1290 return PromiseGetStatus_(this.value_); 1291}; 1292 1293 1294PromiseMirror.prototype.promiseValue = function() { 1295 return MakeMirror(PromiseGetValue_(this.value_)); 1296}; 1297 1298 1299function MapMirror(value) { 1300 %_Call(ObjectMirror, this, value, MirrorType.MAP_TYPE); 1301} 1302inherits(MapMirror, ObjectMirror); 1303 1304 1305/** 1306 * Returns an array of key/value pairs of a map. 1307 * This will keep keys alive for WeakMaps. 1308 * 1309 * @param {number=} opt_limit Max elements to return. 1310 * @returns {Array.<Object>} Array of key/value pairs of a map. 1311 */ 1312MapMirror.prototype.entries = function(opt_limit) { 1313 var result = []; 1314 1315 if (IS_WEAKMAP(this.value_)) { 1316 var entries = %GetWeakMapEntries(this.value_, opt_limit || 0); 1317 for (var i = 0; i < entries.length; i += 2) { 1318 result.push({ 1319 key: entries[i], 1320 value: entries[i + 1] 1321 }); 1322 } 1323 return result; 1324 } 1325 1326 var iter = %_Call(MapEntries, this.value_); 1327 var next; 1328 while ((!opt_limit || result.length < opt_limit) && 1329 !(next = iter.next()).done) { 1330 result.push({ 1331 key: next.value[0], 1332 value: next.value[1] 1333 }); 1334 } 1335 return result; 1336}; 1337 1338 1339function SetMirror(value) { 1340 %_Call(ObjectMirror, this, value, MirrorType.SET_TYPE); 1341} 1342inherits(SetMirror, ObjectMirror); 1343 1344 1345function IteratorGetValues_(iter, next_function, opt_limit) { 1346 var result = []; 1347 var next; 1348 while ((!opt_limit || result.length < opt_limit) && 1349 !(next = %_Call(next_function, iter)).done) { 1350 result.push(next.value); 1351 } 1352 return result; 1353} 1354 1355 1356/** 1357 * Returns an array of elements of a set. 1358 * This will keep elements alive for WeakSets. 1359 * 1360 * @param {number=} opt_limit Max elements to return. 1361 * @returns {Array.<Object>} Array of elements of a set. 1362 */ 1363SetMirror.prototype.values = function(opt_limit) { 1364 if (IS_WEAKSET(this.value_)) { 1365 return %GetWeakSetValues(this.value_, opt_limit || 0); 1366 } 1367 1368 var iter = %_Call(SetValues, this.value_); 1369 return IteratorGetValues_(iter, SetIteratorNext, opt_limit); 1370}; 1371 1372 1373function IteratorMirror(value) { 1374 %_Call(ObjectMirror, this, value, MirrorType.ITERATOR_TYPE); 1375} 1376inherits(IteratorMirror, ObjectMirror); 1377 1378 1379/** 1380 * Returns a preview of elements of an iterator. 1381 * Does not change the backing iterator state. 1382 * 1383 * @param {number=} opt_limit Max elements to return. 1384 * @returns {Array.<Object>} Array of elements of an iterator. 1385 */ 1386IteratorMirror.prototype.preview = function(opt_limit) { 1387 if (IS_MAP_ITERATOR(this.value_)) { 1388 return IteratorGetValues_(%MapIteratorClone(this.value_), 1389 MapIteratorNext, 1390 opt_limit); 1391 } else if (IS_SET_ITERATOR(this.value_)) { 1392 return IteratorGetValues_(%SetIteratorClone(this.value_), 1393 SetIteratorNext, 1394 opt_limit); 1395 } 1396}; 1397 1398 1399/** 1400 * Mirror object for a Generator object. 1401 * @param {Object} data The Generator object 1402 * @constructor 1403 * @extends Mirror 1404 */ 1405function GeneratorMirror(value) { 1406 %_Call(ObjectMirror, this, value, MirrorType.GENERATOR_TYPE); 1407} 1408inherits(GeneratorMirror, ObjectMirror); 1409 1410 1411function GeneratorGetStatus_(value) { 1412 var continuation = %GeneratorGetContinuation(value); 1413 if (continuation < -1) return "running"; 1414 if (continuation == -1) return "closed"; 1415 return "suspended"; 1416} 1417 1418 1419GeneratorMirror.prototype.status = function() { 1420 return GeneratorGetStatus_(this.value_); 1421}; 1422 1423 1424GeneratorMirror.prototype.sourcePosition_ = function() { 1425 return %GeneratorGetSourcePosition(this.value_); 1426}; 1427 1428 1429GeneratorMirror.prototype.sourceLocation = function() { 1430 var pos = this.sourcePosition_(); 1431 if (!IS_UNDEFINED(pos)) { 1432 var script = this.func().script(); 1433 if (script) { 1434 return script.locationFromPosition(pos, true); 1435 } 1436 } 1437}; 1438 1439 1440GeneratorMirror.prototype.func = function() { 1441 if (!this.func_) { 1442 this.func_ = MakeMirror(%GeneratorGetFunction(this.value_)); 1443 } 1444 return this.func_; 1445}; 1446 1447 1448GeneratorMirror.prototype.receiver = function() { 1449 if (!this.receiver_) { 1450 this.receiver_ = MakeMirror(%GeneratorGetReceiver(this.value_)); 1451 } 1452 return this.receiver_; 1453}; 1454 1455 1456/** 1457 * Base mirror object for properties. 1458 * @param {ObjectMirror} mirror The mirror object having this property 1459 * @param {string} name The name of the property 1460 * @param {Array} details Details about the property 1461 * @constructor 1462 * @extends Mirror 1463 */ 1464function PropertyMirror(mirror, name, details) { 1465 %_Call(Mirror, this, MirrorType.PROPERTY_TYPE); 1466 this.mirror_ = mirror; 1467 this.name_ = name; 1468 this.value_ = details[0]; 1469 this.details_ = details[1]; 1470 this.is_interceptor_ = details[2]; 1471 if (details.length > 3) { 1472 this.exception_ = details[3]; 1473 this.getter_ = details[4]; 1474 this.setter_ = details[5]; 1475 } 1476} 1477inherits(PropertyMirror, Mirror); 1478 1479 1480PropertyMirror.prototype.isReadOnly = function() { 1481 return (this.attributes() & PropertyAttribute.ReadOnly) != 0; 1482}; 1483 1484 1485PropertyMirror.prototype.isEnum = function() { 1486 return (this.attributes() & PropertyAttribute.DontEnum) == 0; 1487}; 1488 1489 1490PropertyMirror.prototype.canDelete = function() { 1491 return (this.attributes() & PropertyAttribute.DontDelete) == 0; 1492}; 1493 1494 1495PropertyMirror.prototype.name = function() { 1496 return this.name_; 1497}; 1498 1499 1500PropertyMirror.prototype.toText = function() { 1501 if (IS_SYMBOL(this.name_)) return %SymbolDescriptiveString(this.name_); 1502 return this.name_; 1503}; 1504 1505 1506PropertyMirror.prototype.isIndexed = function() { 1507 for (var i = 0; i < this.name_.length; i++) { 1508 if (this.name_[i] < '0' || '9' < this.name_[i]) { 1509 return false; 1510 } 1511 } 1512 return true; 1513}; 1514 1515 1516PropertyMirror.prototype.value = function() { 1517 return MakeMirror(this.value_, false); 1518}; 1519 1520 1521/** 1522 * Returns whether this property value is an exception. 1523 * @return {booolean} True if this property value is an exception 1524 */ 1525PropertyMirror.prototype.isException = function() { 1526 return this.exception_ ? true : false; 1527}; 1528 1529 1530PropertyMirror.prototype.attributes = function() { 1531 return %DebugPropertyAttributesFromDetails(this.details_); 1532}; 1533 1534 1535PropertyMirror.prototype.propertyType = function() { 1536 return %DebugPropertyTypeFromDetails(this.details_); 1537}; 1538 1539 1540/** 1541 * Returns whether this property has a getter defined through __defineGetter__. 1542 * @return {booolean} True if this property has a getter 1543 */ 1544PropertyMirror.prototype.hasGetter = function() { 1545 return this.getter_ ? true : false; 1546}; 1547 1548 1549/** 1550 * Returns whether this property has a setter defined through __defineSetter__. 1551 * @return {booolean} True if this property has a setter 1552 */ 1553PropertyMirror.prototype.hasSetter = function() { 1554 return this.setter_ ? true : false; 1555}; 1556 1557 1558/** 1559 * Returns the getter for this property defined through __defineGetter__. 1560 * @return {Mirror} FunctionMirror reflecting the getter function or 1561 * UndefinedMirror if there is no getter for this property 1562 */ 1563PropertyMirror.prototype.getter = function() { 1564 if (this.hasGetter()) { 1565 return MakeMirror(this.getter_); 1566 } else { 1567 return GetUndefinedMirror(); 1568 } 1569}; 1570 1571 1572/** 1573 * Returns the setter for this property defined through __defineSetter__. 1574 * @return {Mirror} FunctionMirror reflecting the setter function or 1575 * UndefinedMirror if there is no setter for this property 1576 */ 1577PropertyMirror.prototype.setter = function() { 1578 if (this.hasSetter()) { 1579 return MakeMirror(this.setter_); 1580 } else { 1581 return GetUndefinedMirror(); 1582 } 1583}; 1584 1585 1586/** 1587 * Returns whether this property is natively implemented by the host or a set 1588 * through JavaScript code. 1589 * @return {boolean} True if the property is 1590 * UndefinedMirror if there is no setter for this property 1591 */ 1592PropertyMirror.prototype.isNative = function() { 1593 return this.is_interceptor_ || 1594 ((this.propertyType() == PropertyType.AccessorConstant) && 1595 !this.hasGetter() && !this.hasSetter()); 1596}; 1597 1598 1599/** 1600 * Mirror object for internal properties. Internal property reflects properties 1601 * not accessible from user code such as [[BoundThis]] in bound function. 1602 * Their names are merely symbolic. 1603 * @param {string} name The name of the property 1604 * @param {value} property value 1605 * @constructor 1606 * @extends Mirror 1607 */ 1608function InternalPropertyMirror(name, value) { 1609 %_Call(Mirror, this, MirrorType.INTERNAL_PROPERTY_TYPE); 1610 this.name_ = name; 1611 this.value_ = value; 1612} 1613inherits(InternalPropertyMirror, Mirror); 1614 1615 1616InternalPropertyMirror.prototype.name = function() { 1617 return this.name_; 1618}; 1619 1620 1621InternalPropertyMirror.prototype.value = function() { 1622 return MakeMirror(this.value_, false); 1623}; 1624 1625 1626var kFrameDetailsFrameIdIndex = 0; 1627var kFrameDetailsReceiverIndex = 1; 1628var kFrameDetailsFunctionIndex = 2; 1629var kFrameDetailsArgumentCountIndex = 3; 1630var kFrameDetailsLocalCountIndex = 4; 1631var kFrameDetailsSourcePositionIndex = 5; 1632var kFrameDetailsConstructCallIndex = 6; 1633var kFrameDetailsAtReturnIndex = 7; 1634var kFrameDetailsFlagsIndex = 8; 1635var kFrameDetailsFirstDynamicIndex = 9; 1636 1637var kFrameDetailsNameIndex = 0; 1638var kFrameDetailsValueIndex = 1; 1639var kFrameDetailsNameValueSize = 2; 1640 1641var kFrameDetailsFlagDebuggerFrameMask = 1 << 0; 1642var kFrameDetailsFlagOptimizedFrameMask = 1 << 1; 1643var kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2; 1644 1645/** 1646 * Wrapper for the frame details information retreived from the VM. The frame 1647 * details from the VM is an array with the following content. See runtime.cc 1648 * Runtime_GetFrameDetails. 1649 * 0: Id 1650 * 1: Receiver 1651 * 2: Function 1652 * 3: Argument count 1653 * 4: Local count 1654 * 5: Source position 1655 * 6: Construct call 1656 * 7: Is at return 1657 * 8: Flags (debugger frame, optimized frame, inlined frame index) 1658 * Arguments name, value 1659 * Locals name, value 1660 * Return value if any 1661 * @param {number} break_id Current break id 1662 * @param {number} index Frame number 1663 * @constructor 1664 */ 1665function FrameDetails(break_id, index) { 1666 this.break_id_ = break_id; 1667 this.details_ = %GetFrameDetails(break_id, index); 1668} 1669 1670 1671FrameDetails.prototype.frameId = function() { 1672 %CheckExecutionState(this.break_id_); 1673 return this.details_[kFrameDetailsFrameIdIndex]; 1674}; 1675 1676 1677FrameDetails.prototype.receiver = function() { 1678 %CheckExecutionState(this.break_id_); 1679 return this.details_[kFrameDetailsReceiverIndex]; 1680}; 1681 1682 1683FrameDetails.prototype.func = function() { 1684 %CheckExecutionState(this.break_id_); 1685 return this.details_[kFrameDetailsFunctionIndex]; 1686}; 1687 1688 1689FrameDetails.prototype.isConstructCall = function() { 1690 %CheckExecutionState(this.break_id_); 1691 return this.details_[kFrameDetailsConstructCallIndex]; 1692}; 1693 1694 1695FrameDetails.prototype.isAtReturn = function() { 1696 %CheckExecutionState(this.break_id_); 1697 return this.details_[kFrameDetailsAtReturnIndex]; 1698}; 1699 1700 1701FrameDetails.prototype.isDebuggerFrame = function() { 1702 %CheckExecutionState(this.break_id_); 1703 var f = kFrameDetailsFlagDebuggerFrameMask; 1704 return (this.details_[kFrameDetailsFlagsIndex] & f) == f; 1705}; 1706 1707 1708FrameDetails.prototype.isOptimizedFrame = function() { 1709 %CheckExecutionState(this.break_id_); 1710 var f = kFrameDetailsFlagOptimizedFrameMask; 1711 return (this.details_[kFrameDetailsFlagsIndex] & f) == f; 1712}; 1713 1714 1715FrameDetails.prototype.isInlinedFrame = function() { 1716 return this.inlinedFrameIndex() > 0; 1717}; 1718 1719 1720FrameDetails.prototype.inlinedFrameIndex = function() { 1721 %CheckExecutionState(this.break_id_); 1722 var f = kFrameDetailsFlagInlinedFrameIndexMask; 1723 return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2; 1724}; 1725 1726 1727FrameDetails.prototype.argumentCount = function() { 1728 %CheckExecutionState(this.break_id_); 1729 return this.details_[kFrameDetailsArgumentCountIndex]; 1730}; 1731 1732 1733FrameDetails.prototype.argumentName = function(index) { 1734 %CheckExecutionState(this.break_id_); 1735 if (index >= 0 && index < this.argumentCount()) { 1736 return this.details_[kFrameDetailsFirstDynamicIndex + 1737 index * kFrameDetailsNameValueSize + 1738 kFrameDetailsNameIndex]; 1739 } 1740}; 1741 1742 1743FrameDetails.prototype.argumentValue = function(index) { 1744 %CheckExecutionState(this.break_id_); 1745 if (index >= 0 && index < this.argumentCount()) { 1746 return this.details_[kFrameDetailsFirstDynamicIndex + 1747 index * kFrameDetailsNameValueSize + 1748 kFrameDetailsValueIndex]; 1749 } 1750}; 1751 1752 1753FrameDetails.prototype.localCount = function() { 1754 %CheckExecutionState(this.break_id_); 1755 return this.details_[kFrameDetailsLocalCountIndex]; 1756}; 1757 1758 1759FrameDetails.prototype.sourcePosition = function() { 1760 %CheckExecutionState(this.break_id_); 1761 return this.details_[kFrameDetailsSourcePositionIndex]; 1762}; 1763 1764 1765FrameDetails.prototype.localName = function(index) { 1766 %CheckExecutionState(this.break_id_); 1767 if (index >= 0 && index < this.localCount()) { 1768 var locals_offset = kFrameDetailsFirstDynamicIndex + 1769 this.argumentCount() * kFrameDetailsNameValueSize; 1770 return this.details_[locals_offset + 1771 index * kFrameDetailsNameValueSize + 1772 kFrameDetailsNameIndex]; 1773 } 1774}; 1775 1776 1777FrameDetails.prototype.localValue = function(index) { 1778 %CheckExecutionState(this.break_id_); 1779 if (index >= 0 && index < this.localCount()) { 1780 var locals_offset = kFrameDetailsFirstDynamicIndex + 1781 this.argumentCount() * kFrameDetailsNameValueSize; 1782 return this.details_[locals_offset + 1783 index * kFrameDetailsNameValueSize + 1784 kFrameDetailsValueIndex]; 1785 } 1786}; 1787 1788 1789FrameDetails.prototype.returnValue = function() { 1790 %CheckExecutionState(this.break_id_); 1791 var return_value_offset = 1792 kFrameDetailsFirstDynamicIndex + 1793 (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize; 1794 if (this.details_[kFrameDetailsAtReturnIndex]) { 1795 return this.details_[return_value_offset]; 1796 } 1797}; 1798 1799 1800FrameDetails.prototype.scopeCount = function() { 1801 if (IS_UNDEFINED(this.scopeCount_)) { 1802 this.scopeCount_ = %GetScopeCount(this.break_id_, this.frameId()); 1803 } 1804 return this.scopeCount_; 1805}; 1806 1807 1808/** 1809 * Mirror object for stack frames. 1810 * @param {number} break_id The break id in the VM for which this frame is 1811 valid 1812 * @param {number} index The frame index (top frame is index 0) 1813 * @constructor 1814 * @extends Mirror 1815 */ 1816function FrameMirror(break_id, index) { 1817 %_Call(Mirror, this, MirrorType.FRAME_TYPE); 1818 this.break_id_ = break_id; 1819 this.index_ = index; 1820 this.details_ = new FrameDetails(break_id, index); 1821} 1822inherits(FrameMirror, Mirror); 1823 1824 1825FrameMirror.prototype.details = function() { 1826 return this.details_; 1827}; 1828 1829 1830FrameMirror.prototype.index = function() { 1831 return this.index_; 1832}; 1833 1834 1835FrameMirror.prototype.func = function() { 1836 if (this.func_) { 1837 return this.func_; 1838 } 1839 1840 // Get the function for this frame from the VM. 1841 var f = this.details_.func(); 1842 1843 // Create a function mirror. NOTE: MakeMirror cannot be used here as the 1844 // value returned from the VM might be a string if the function for the 1845 // frame is unresolved. 1846 if (IS_FUNCTION(f)) { 1847 return this.func_ = MakeMirror(f); 1848 } else { 1849 return new UnresolvedFunctionMirror(f); 1850 } 1851}; 1852 1853 1854FrameMirror.prototype.receiver = function() { 1855 return MakeMirror(this.details_.receiver()); 1856}; 1857 1858 1859FrameMirror.prototype.isConstructCall = function() { 1860 return this.details_.isConstructCall(); 1861}; 1862 1863 1864FrameMirror.prototype.isAtReturn = function() { 1865 return this.details_.isAtReturn(); 1866}; 1867 1868 1869FrameMirror.prototype.isDebuggerFrame = function() { 1870 return this.details_.isDebuggerFrame(); 1871}; 1872 1873 1874FrameMirror.prototype.isOptimizedFrame = function() { 1875 return this.details_.isOptimizedFrame(); 1876}; 1877 1878 1879FrameMirror.prototype.isInlinedFrame = function() { 1880 return this.details_.isInlinedFrame(); 1881}; 1882 1883 1884FrameMirror.prototype.inlinedFrameIndex = function() { 1885 return this.details_.inlinedFrameIndex(); 1886}; 1887 1888 1889FrameMirror.prototype.argumentCount = function() { 1890 return this.details_.argumentCount(); 1891}; 1892 1893 1894FrameMirror.prototype.argumentName = function(index) { 1895 return this.details_.argumentName(index); 1896}; 1897 1898 1899FrameMirror.prototype.argumentValue = function(index) { 1900 return MakeMirror(this.details_.argumentValue(index)); 1901}; 1902 1903 1904FrameMirror.prototype.localCount = function() { 1905 return this.details_.localCount(); 1906}; 1907 1908 1909FrameMirror.prototype.localName = function(index) { 1910 return this.details_.localName(index); 1911}; 1912 1913 1914FrameMirror.prototype.localValue = function(index) { 1915 return MakeMirror(this.details_.localValue(index)); 1916}; 1917 1918 1919FrameMirror.prototype.returnValue = function() { 1920 return MakeMirror(this.details_.returnValue()); 1921}; 1922 1923 1924FrameMirror.prototype.sourcePosition = function() { 1925 return this.details_.sourcePosition(); 1926}; 1927 1928 1929FrameMirror.prototype.sourceLocation = function() { 1930 var func = this.func(); 1931 if (func.resolved()) { 1932 var script = func.script(); 1933 if (script) { 1934 return script.locationFromPosition(this.sourcePosition(), true); 1935 } 1936 } 1937}; 1938 1939 1940FrameMirror.prototype.sourceLine = function() { 1941 var location = this.sourceLocation(); 1942 if (location) { 1943 return location.line; 1944 } 1945}; 1946 1947 1948FrameMirror.prototype.sourceColumn = function() { 1949 var location = this.sourceLocation(); 1950 if (location) { 1951 return location.column; 1952 } 1953}; 1954 1955 1956FrameMirror.prototype.sourceLineText = function() { 1957 var location = this.sourceLocation(); 1958 if (location) { 1959 return location.sourceText(); 1960 } 1961}; 1962 1963 1964FrameMirror.prototype.scopeCount = function() { 1965 return this.details_.scopeCount(); 1966}; 1967 1968 1969FrameMirror.prototype.scope = function(index) { 1970 return new ScopeMirror(this, UNDEFINED, index); 1971}; 1972 1973 1974FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) { 1975 var scopeDetails = %GetAllScopesDetails(this.break_id_, 1976 this.details_.frameId(), 1977 this.details_.inlinedFrameIndex(), 1978 !!opt_ignore_nested_scopes); 1979 var result = []; 1980 for (var i = 0; i < scopeDetails.length; ++i) { 1981 result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i])); 1982 } 1983 return result; 1984}; 1985 1986 1987FrameMirror.prototype.evaluate = function(source, disable_break, 1988 opt_context_object) { 1989 return MakeMirror(%DebugEvaluate(this.break_id_, 1990 this.details_.frameId(), 1991 this.details_.inlinedFrameIndex(), 1992 source, 1993 TO_BOOLEAN(disable_break), 1994 opt_context_object)); 1995}; 1996 1997 1998FrameMirror.prototype.invocationText = function() { 1999 // Format frame invoaction (receiver, function and arguments). 2000 var result = ''; 2001 var func = this.func(); 2002 var receiver = this.receiver(); 2003 if (this.isConstructCall()) { 2004 // For constructor frames display new followed by the function name. 2005 result += 'new '; 2006 result += func.name() ? func.name() : '[anonymous]'; 2007 } else if (this.isDebuggerFrame()) { 2008 result += '[debugger]'; 2009 } else { 2010 // If the receiver has a className which is 'global' don't display it. 2011 var display_receiver = 2012 !receiver.className || (receiver.className() != 'global'); 2013 if (display_receiver) { 2014 result += receiver.toText(); 2015 } 2016 // Try to find the function as a property in the receiver. Include the 2017 // prototype chain in the lookup. 2018 var property = GetUndefinedMirror(); 2019 if (receiver.isObject()) { 2020 for (var r = receiver; 2021 !r.isNull() && property.isUndefined(); 2022 r = r.protoObject()) { 2023 property = r.lookupProperty(func); 2024 } 2025 } 2026 if (!property.isUndefined()) { 2027 // The function invoked was found on the receiver. Use the property name 2028 // for the backtrace. 2029 if (!property.isIndexed()) { 2030 if (display_receiver) { 2031 result += '.'; 2032 } 2033 result += property.toText(); 2034 } else { 2035 result += '['; 2036 result += property.toText(); 2037 result += ']'; 2038 } 2039 // Also known as - if the name in the function doesn't match the name 2040 // under which it was looked up. 2041 if (func.name() && func.name() != property.name()) { 2042 result += '(aka ' + func.name() + ')'; 2043 } 2044 } else { 2045 // The function invoked was not found on the receiver. Use the function 2046 // name if available for the backtrace. 2047 if (display_receiver) { 2048 result += '.'; 2049 } 2050 result += func.name() ? func.name() : '[anonymous]'; 2051 } 2052 } 2053 2054 // Render arguments for normal frames. 2055 if (!this.isDebuggerFrame()) { 2056 result += '('; 2057 for (var i = 0; i < this.argumentCount(); i++) { 2058 if (i != 0) result += ', '; 2059 if (this.argumentName(i)) { 2060 result += this.argumentName(i); 2061 result += '='; 2062 } 2063 result += this.argumentValue(i).toText(); 2064 } 2065 result += ')'; 2066 } 2067 2068 if (this.isAtReturn()) { 2069 result += ' returning '; 2070 result += this.returnValue().toText(); 2071 } 2072 2073 return result; 2074}; 2075 2076 2077FrameMirror.prototype.sourceAndPositionText = function() { 2078 // Format source and position. 2079 var result = ''; 2080 var func = this.func(); 2081 if (func.resolved()) { 2082 var script = func.script(); 2083 if (script) { 2084 if (script.name()) { 2085 result += script.name(); 2086 } else { 2087 result += '[unnamed]'; 2088 } 2089 if (!this.isDebuggerFrame()) { 2090 var location = this.sourceLocation(); 2091 result += ' line '; 2092 result += !IS_UNDEFINED(location) ? (location.line + 1) : '?'; 2093 result += ' column '; 2094 result += !IS_UNDEFINED(location) ? (location.column + 1) : '?'; 2095 if (!IS_UNDEFINED(this.sourcePosition())) { 2096 result += ' (position ' + (this.sourcePosition() + 1) + ')'; 2097 } 2098 } 2099 } else { 2100 result += '[no source]'; 2101 } 2102 } else { 2103 result += '[unresolved]'; 2104 } 2105 2106 return result; 2107}; 2108 2109 2110FrameMirror.prototype.localsText = function() { 2111 // Format local variables. 2112 var result = ''; 2113 var locals_count = this.localCount(); 2114 if (locals_count > 0) { 2115 for (var i = 0; i < locals_count; ++i) { 2116 result += ' var '; 2117 result += this.localName(i); 2118 result += ' = '; 2119 result += this.localValue(i).toText(); 2120 if (i < locals_count - 1) result += '\n'; 2121 } 2122 } 2123 2124 return result; 2125}; 2126 2127 2128FrameMirror.prototype.restart = function() { 2129 var result = %LiveEditRestartFrame(this.break_id_, this.index_); 2130 if (IS_UNDEFINED(result)) { 2131 result = "Failed to find requested frame"; 2132 } 2133 return result; 2134}; 2135 2136 2137FrameMirror.prototype.toText = function(opt_locals) { 2138 var result = ''; 2139 result += '#' + (this.index() <= 9 ? '0' : '') + this.index(); 2140 result += ' '; 2141 result += this.invocationText(); 2142 result += ' '; 2143 result += this.sourceAndPositionText(); 2144 if (opt_locals) { 2145 result += '\n'; 2146 result += this.localsText(); 2147 } 2148 return result; 2149}; 2150 2151 2152// This indexes correspond definitions in debug-scopes.h. 2153var kScopeDetailsTypeIndex = 0; 2154var kScopeDetailsObjectIndex = 1; 2155var kScopeDetailsNameIndex = 2; 2156var kScopeDetailsStartPositionIndex = 3; 2157var kScopeDetailsEndPositionIndex = 4; 2158var kScopeDetailsFunctionIndex = 5; 2159 2160function ScopeDetails(frame, fun, index, opt_details) { 2161 if (frame) { 2162 this.break_id_ = frame.break_id_; 2163 this.details_ = opt_details || 2164 %GetScopeDetails(frame.break_id_, 2165 frame.details_.frameId(), 2166 frame.details_.inlinedFrameIndex(), 2167 index); 2168 this.frame_id_ = frame.details_.frameId(); 2169 this.inlined_frame_id_ = frame.details_.inlinedFrameIndex(); 2170 } else { 2171 this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index); 2172 this.fun_value_ = fun.value(); 2173 this.break_id_ = UNDEFINED; 2174 } 2175 this.index_ = index; 2176} 2177 2178 2179ScopeDetails.prototype.type = function() { 2180 if (!IS_UNDEFINED(this.break_id_)) { 2181 %CheckExecutionState(this.break_id_); 2182 } 2183 return this.details_[kScopeDetailsTypeIndex]; 2184}; 2185 2186 2187ScopeDetails.prototype.object = function() { 2188 if (!IS_UNDEFINED(this.break_id_)) { 2189 %CheckExecutionState(this.break_id_); 2190 } 2191 return this.details_[kScopeDetailsObjectIndex]; 2192}; 2193 2194 2195ScopeDetails.prototype.name = function() { 2196 if (!IS_UNDEFINED(this.break_id_)) { 2197 %CheckExecutionState(this.break_id_); 2198 } 2199 return this.details_[kScopeDetailsNameIndex]; 2200}; 2201 2202 2203ScopeDetails.prototype.startPosition = function() { 2204 if (!IS_UNDEFINED(this.break_id_)) { 2205 %CheckExecutionState(this.break_id_); 2206 } 2207 return this.details_[kScopeDetailsStartPositionIndex]; 2208} 2209 2210 2211ScopeDetails.prototype.endPosition = function() { 2212 if (!IS_UNDEFINED(this.break_id_)) { 2213 %CheckExecutionState(this.break_id_); 2214 } 2215 return this.details_[kScopeDetailsEndPositionIndex]; 2216} 2217 2218ScopeDetails.prototype.func = function() { 2219 if (!IS_UNDEFINED(this.break_id_)) { 2220 %CheckExecutionState(this.break_id_); 2221 } 2222 return this.details_[kScopeDetailsFunctionIndex]; 2223} 2224 2225 2226ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) { 2227 var raw_res; 2228 if (!IS_UNDEFINED(this.break_id_)) { 2229 %CheckExecutionState(this.break_id_); 2230 raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_, 2231 this.inlined_frame_id_, this.index_, name, new_value); 2232 } else { 2233 raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_, 2234 name, new_value); 2235 } 2236 if (!raw_res) throw MakeError(kDebugger, "Failed to set variable value"); 2237}; 2238 2239 2240/** 2241 * Mirror object for scope of frame or function. Either frame or function must 2242 * be specified. 2243 * @param {FrameMirror} frame The frame this scope is a part of 2244 * @param {FunctionMirror} function The function this scope is a part of 2245 * @param {number} index The scope index in the frame 2246 * @param {Array=} opt_details Raw scope details data 2247 * @constructor 2248 * @extends Mirror 2249 */ 2250function ScopeMirror(frame, fun, index, opt_details) { 2251 %_Call(Mirror, this, MirrorType.SCOPE_TYPE); 2252 if (frame) { 2253 this.frame_index_ = frame.index_; 2254 } else { 2255 this.frame_index_ = UNDEFINED; 2256 } 2257 this.scope_index_ = index; 2258 this.details_ = new ScopeDetails(frame, fun, index, opt_details); 2259} 2260inherits(ScopeMirror, Mirror); 2261 2262 2263ScopeMirror.prototype.details = function() { 2264 return this.details_; 2265}; 2266 2267 2268ScopeMirror.prototype.frameIndex = function() { 2269 return this.frame_index_; 2270}; 2271 2272 2273ScopeMirror.prototype.scopeIndex = function() { 2274 return this.scope_index_; 2275}; 2276 2277 2278ScopeMirror.prototype.scopeType = function() { 2279 return this.details_.type(); 2280}; 2281 2282 2283ScopeMirror.prototype.scopeObject = function() { 2284 // For local, closure and script scopes create a transient mirror 2285 // as these objects are created on the fly materializing the local 2286 // or closure scopes and therefore will not preserve identity. 2287 var transient = this.scopeType() == ScopeType.Local || 2288 this.scopeType() == ScopeType.Closure || 2289 this.scopeType() == ScopeType.Script; 2290 return MakeMirror(this.details_.object(), transient); 2291}; 2292 2293 2294ScopeMirror.prototype.setVariableValue = function(name, new_value) { 2295 this.details_.setVariableValueImpl(name, new_value); 2296}; 2297 2298 2299/** 2300 * Mirror object for script source. 2301 * @param {Script} script The script object 2302 * @constructor 2303 * @extends Mirror 2304 */ 2305function ScriptMirror(script) { 2306 %_Call(Mirror, this, MirrorType.SCRIPT_TYPE); 2307 this.script_ = script; 2308 this.context_ = new ContextMirror(script.context_data); 2309 this.allocateHandle_(); 2310} 2311inherits(ScriptMirror, Mirror); 2312 2313 2314ScriptMirror.prototype.value = function() { 2315 return this.script_; 2316}; 2317 2318 2319ScriptMirror.prototype.name = function() { 2320 return this.script_.name || this.script_.nameOrSourceURL(); 2321}; 2322 2323 2324ScriptMirror.prototype.id = function() { 2325 return this.script_.id; 2326}; 2327 2328 2329ScriptMirror.prototype.source = function() { 2330 return this.script_.source; 2331}; 2332 2333 2334ScriptMirror.prototype.setSource = function(source) { 2335 %DebugSetScriptSource(this.script_, source); 2336}; 2337 2338 2339ScriptMirror.prototype.lineOffset = function() { 2340 return this.script_.line_offset; 2341}; 2342 2343 2344ScriptMirror.prototype.columnOffset = function() { 2345 return this.script_.column_offset; 2346}; 2347 2348 2349ScriptMirror.prototype.data = function() { 2350 return this.script_.data; 2351}; 2352 2353 2354ScriptMirror.prototype.scriptType = function() { 2355 return this.script_.type; 2356}; 2357 2358 2359ScriptMirror.prototype.compilationType = function() { 2360 return this.script_.compilation_type; 2361}; 2362 2363 2364ScriptMirror.prototype.lineCount = function() { 2365 return this.script_.lineCount(); 2366}; 2367 2368 2369ScriptMirror.prototype.locationFromPosition = function( 2370 position, include_resource_offset) { 2371 return this.script_.locationFromPosition(position, include_resource_offset); 2372}; 2373 2374 2375ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) { 2376 return this.script_.sourceSlice(opt_from_line, opt_to_line); 2377}; 2378 2379 2380ScriptMirror.prototype.context = function() { 2381 return this.context_; 2382}; 2383 2384 2385ScriptMirror.prototype.evalFromScript = function() { 2386 return MakeMirror(this.script_.eval_from_script); 2387}; 2388 2389 2390ScriptMirror.prototype.evalFromFunctionName = function() { 2391 return MakeMirror(this.script_.eval_from_function_name); 2392}; 2393 2394 2395ScriptMirror.prototype.evalFromLocation = function() { 2396 var eval_from_script = this.evalFromScript(); 2397 if (!eval_from_script.isUndefined()) { 2398 var position = this.script_.eval_from_script_position; 2399 return eval_from_script.locationFromPosition(position, true); 2400 } 2401}; 2402 2403 2404ScriptMirror.prototype.toText = function() { 2405 var result = ''; 2406 result += this.name(); 2407 result += ' (lines: '; 2408 if (this.lineOffset() > 0) { 2409 result += this.lineOffset(); 2410 result += '-'; 2411 result += this.lineOffset() + this.lineCount() - 1; 2412 } else { 2413 result += this.lineCount(); 2414 } 2415 result += ')'; 2416 return result; 2417}; 2418 2419 2420/** 2421 * Mirror object for context. 2422 * @param {Object} data The context data 2423 * @constructor 2424 * @extends Mirror 2425 */ 2426function ContextMirror(data) { 2427 %_Call(Mirror, this, MirrorType.CONTEXT_TYPE); 2428 this.data_ = data; 2429 this.allocateHandle_(); 2430} 2431inherits(ContextMirror, Mirror); 2432 2433 2434ContextMirror.prototype.data = function() { 2435 return this.data_; 2436}; 2437 2438 2439/** 2440 * Returns a mirror serializer 2441 * 2442 * @param {boolean} details Set to true to include details 2443 * @param {Object} options Options comtrolling the serialization 2444 * The following options can be set: 2445 * includeSource: include ths full source of scripts 2446 * @returns {MirrorSerializer} mirror serializer 2447 */ 2448function MakeMirrorSerializer(details, options) { 2449 return new JSONProtocolSerializer(details, options); 2450} 2451 2452 2453/** 2454 * Object for serializing a mirror objects and its direct references. 2455 * @param {boolean} details Indicates whether to include details for the mirror 2456 * serialized 2457 * @constructor 2458 */ 2459function JSONProtocolSerializer(details, options) { 2460 this.details_ = details; 2461 this.options_ = options; 2462 this.mirrors_ = [ ]; 2463} 2464 2465 2466/** 2467 * Returns a serialization of an object reference. The referenced object are 2468 * added to the serialization state. 2469 * 2470 * @param {Mirror} mirror The mirror to serialize 2471 * @returns {String} JSON serialization 2472 */ 2473JSONProtocolSerializer.prototype.serializeReference = function(mirror) { 2474 return this.serialize_(mirror, true, true); 2475}; 2476 2477 2478/** 2479 * Returns a serialization of an object value. The referenced objects are 2480 * added to the serialization state. 2481 * 2482 * @param {Mirror} mirror The mirror to serialize 2483 * @returns {String} JSON serialization 2484 */ 2485JSONProtocolSerializer.prototype.serializeValue = function(mirror) { 2486 var json = this.serialize_(mirror, false, true); 2487 return json; 2488}; 2489 2490 2491/** 2492 * Returns a serialization of all the objects referenced. 2493 * 2494 * @param {Mirror} mirror The mirror to serialize. 2495 * @returns {Array.<Object>} Array of the referenced objects converted to 2496 * protcol objects. 2497 */ 2498JSONProtocolSerializer.prototype.serializeReferencedObjects = function() { 2499 // Collect the protocol representation of the referenced objects in an array. 2500 var content = []; 2501 2502 // Get the number of referenced objects. 2503 var count = this.mirrors_.length; 2504 2505 for (var i = 0; i < count; i++) { 2506 content.push(this.serialize_(this.mirrors_[i], false, false)); 2507 } 2508 2509 return content; 2510}; 2511 2512 2513JSONProtocolSerializer.prototype.includeSource_ = function() { 2514 return this.options_ && this.options_.includeSource; 2515}; 2516 2517 2518JSONProtocolSerializer.prototype.inlineRefs_ = function() { 2519 return this.options_ && this.options_.inlineRefs; 2520}; 2521 2522 2523JSONProtocolSerializer.prototype.maxStringLength_ = function() { 2524 if (IS_UNDEFINED(this.options_) || 2525 IS_UNDEFINED(this.options_.maxStringLength)) { 2526 return kMaxProtocolStringLength; 2527 } 2528 return this.options_.maxStringLength; 2529}; 2530 2531 2532JSONProtocolSerializer.prototype.add_ = function(mirror) { 2533 // If this mirror is already in the list just return. 2534 for (var i = 0; i < this.mirrors_.length; i++) { 2535 if (this.mirrors_[i] === mirror) { 2536 return; 2537 } 2538 } 2539 2540 // Add the mirror to the list of mirrors to be serialized. 2541 this.mirrors_.push(mirror); 2542}; 2543 2544 2545/** 2546 * Formats mirror object to protocol reference object with some data that can 2547 * be used to display the value in debugger. 2548 * @param {Mirror} mirror Mirror to serialize. 2549 * @return {Object} Protocol reference object. 2550 */ 2551JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ = 2552 function(mirror) { 2553 var o = {}; 2554 o.ref = mirror.handle(); 2555 o.type = mirror.type(); 2556 switch (mirror.type()) { 2557 case MirrorType.UNDEFINED_TYPE: 2558 case MirrorType.NULL_TYPE: 2559 case MirrorType.BOOLEAN_TYPE: 2560 case MirrorType.NUMBER_TYPE: 2561 o.value = mirror.value(); 2562 break; 2563 case MirrorType.STRING_TYPE: 2564 o.value = mirror.getTruncatedValue(this.maxStringLength_()); 2565 break; 2566 case MirrorType.SYMBOL_TYPE: 2567 o.description = mirror.description(); 2568 break; 2569 case MirrorType.FUNCTION_TYPE: 2570 o.name = mirror.name(); 2571 o.inferredName = mirror.inferredName(); 2572 if (mirror.script()) { 2573 o.scriptId = mirror.script().id(); 2574 } 2575 break; 2576 case MirrorType.ERROR_TYPE: 2577 case MirrorType.REGEXP_TYPE: 2578 o.value = mirror.toText(); 2579 break; 2580 case MirrorType.OBJECT_TYPE: 2581 o.className = mirror.className(); 2582 break; 2583 } 2584 return o; 2585}; 2586 2587 2588JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, 2589 details) { 2590 // If serializing a reference to a mirror just return the reference and add 2591 // the mirror to the referenced mirrors. 2592 if (reference && 2593 (mirror.isValue() || mirror.isScript() || mirror.isContext())) { 2594 if (this.inlineRefs_() && mirror.isValue()) { 2595 return this.serializeReferenceWithDisplayData_(mirror); 2596 } else { 2597 this.add_(mirror); 2598 return {'ref' : mirror.handle()}; 2599 } 2600 } 2601 2602 // Collect the JSON property/value pairs. 2603 var content = {}; 2604 2605 // Add the mirror handle. 2606 if (mirror.isValue() || mirror.isScript() || mirror.isContext()) { 2607 content.handle = mirror.handle(); 2608 } 2609 2610 // Always add the type. 2611 content.type = mirror.type(); 2612 2613 switch (mirror.type()) { 2614 case MirrorType.UNDEFINED_TYPE: 2615 case MirrorType.NULL_TYPE: 2616 // Undefined and null are represented just by their type. 2617 break; 2618 2619 case MirrorType.BOOLEAN_TYPE: 2620 // Boolean values are simply represented by their value. 2621 content.value = mirror.value(); 2622 break; 2623 2624 case MirrorType.NUMBER_TYPE: 2625 // Number values are simply represented by their value. 2626 content.value = NumberToJSON_(mirror.value()); 2627 break; 2628 2629 case MirrorType.STRING_TYPE: 2630 // String values might have their value cropped to keep down size. 2631 if (this.maxStringLength_() != -1 && 2632 mirror.length() > this.maxStringLength_()) { 2633 var str = mirror.getTruncatedValue(this.maxStringLength_()); 2634 content.value = str; 2635 content.fromIndex = 0; 2636 content.toIndex = this.maxStringLength_(); 2637 } else { 2638 content.value = mirror.value(); 2639 } 2640 content.length = mirror.length(); 2641 break; 2642 2643 case MirrorType.SYMBOL_TYPE: 2644 content.description = mirror.description(); 2645 break; 2646 2647 case MirrorType.OBJECT_TYPE: 2648 case MirrorType.FUNCTION_TYPE: 2649 case MirrorType.ERROR_TYPE: 2650 case MirrorType.REGEXP_TYPE: 2651 case MirrorType.PROMISE_TYPE: 2652 case MirrorType.GENERATOR_TYPE: 2653 // Add object representation. 2654 this.serializeObject_(mirror, content, details); 2655 break; 2656 2657 case MirrorType.PROPERTY_TYPE: 2658 case MirrorType.INTERNAL_PROPERTY_TYPE: 2659 throw MakeError(kDebugger, 2660 'PropertyMirror cannot be serialized independently'); 2661 break; 2662 2663 case MirrorType.FRAME_TYPE: 2664 // Add object representation. 2665 this.serializeFrame_(mirror, content); 2666 break; 2667 2668 case MirrorType.SCOPE_TYPE: 2669 // Add object representation. 2670 this.serializeScope_(mirror, content); 2671 break; 2672 2673 case MirrorType.SCRIPT_TYPE: 2674 // Script is represented by id, name and source attributes. 2675 if (mirror.name()) { 2676 content.name = mirror.name(); 2677 } 2678 content.id = mirror.id(); 2679 content.lineOffset = mirror.lineOffset(); 2680 content.columnOffset = mirror.columnOffset(); 2681 content.lineCount = mirror.lineCount(); 2682 if (mirror.data()) { 2683 content.data = mirror.data(); 2684 } 2685 if (this.includeSource_()) { 2686 content.source = mirror.source(); 2687 } else { 2688 var sourceStart = mirror.source().substring(0, 80); 2689 content.sourceStart = sourceStart; 2690 } 2691 content.sourceLength = mirror.source().length; 2692 content.scriptType = mirror.scriptType(); 2693 content.compilationType = mirror.compilationType(); 2694 // For compilation type eval emit information on the script from which 2695 // eval was called if a script is present. 2696 if (mirror.compilationType() == 1 && 2697 mirror.evalFromScript()) { 2698 content.evalFromScript = 2699 this.serializeReference(mirror.evalFromScript()); 2700 var evalFromLocation = mirror.evalFromLocation(); 2701 if (evalFromLocation) { 2702 content.evalFromLocation = { line: evalFromLocation.line, 2703 column: evalFromLocation.column }; 2704 } 2705 if (mirror.evalFromFunctionName()) { 2706 content.evalFromFunctionName = mirror.evalFromFunctionName(); 2707 } 2708 } 2709 if (mirror.context()) { 2710 content.context = this.serializeReference(mirror.context()); 2711 } 2712 break; 2713 2714 case MirrorType.CONTEXT_TYPE: 2715 content.data = mirror.data(); 2716 break; 2717 } 2718 2719 // Always add the text representation. 2720 content.text = mirror.toText(); 2721 2722 // Create and return the JSON string. 2723 return content; 2724}; 2725 2726 2727/** 2728 * Serialize object information to the following JSON format. 2729 * 2730 * {"className":"<class name>", 2731 * "constructorFunction":{"ref":<number>}, 2732 * "protoObject":{"ref":<number>}, 2733 * "prototypeObject":{"ref":<number>}, 2734 * "namedInterceptor":<boolean>, 2735 * "indexedInterceptor":<boolean>, 2736 * "properties":[<properties>], 2737 * "internalProperties":[<internal properties>]} 2738 */ 2739JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content, 2740 details) { 2741 // Add general object properties. 2742 content.className = mirror.className(); 2743 content.constructorFunction = 2744 this.serializeReference(mirror.constructorFunction()); 2745 content.protoObject = this.serializeReference(mirror.protoObject()); 2746 content.prototypeObject = this.serializeReference(mirror.prototypeObject()); 2747 2748 // Add flags to indicate whether there are interceptors. 2749 if (mirror.hasNamedInterceptor()) { 2750 content.namedInterceptor = true; 2751 } 2752 if (mirror.hasIndexedInterceptor()) { 2753 content.indexedInterceptor = true; 2754 } 2755 2756 if (mirror.isFunction()) { 2757 // Add function specific properties. 2758 content.name = mirror.name(); 2759 if (!IS_UNDEFINED(mirror.inferredName())) { 2760 content.inferredName = mirror.inferredName(); 2761 } 2762 content.resolved = mirror.resolved(); 2763 if (mirror.resolved()) { 2764 content.source = mirror.source(); 2765 } 2766 if (mirror.script()) { 2767 content.script = this.serializeReference(mirror.script()); 2768 content.scriptId = mirror.script().id(); 2769 2770 serializeLocationFields(mirror.sourceLocation(), content); 2771 } 2772 2773 content.scopes = []; 2774 for (var i = 0; i < mirror.scopeCount(); i++) { 2775 var scope = mirror.scope(i); 2776 content.scopes.push({ 2777 type: scope.scopeType(), 2778 index: i 2779 }); 2780 } 2781 } 2782 2783 if (mirror.isGenerator()) { 2784 // Add generator specific properties. 2785 2786 // Either 'running', 'closed', or 'suspended'. 2787 content.status = mirror.status(); 2788 2789 content.func = this.serializeReference(mirror.func()) 2790 content.receiver = this.serializeReference(mirror.receiver()) 2791 2792 // If the generator is suspended, the content add line/column properties. 2793 serializeLocationFields(mirror.sourceLocation(), content); 2794 2795 // TODO(wingo): Also serialize a reference to the context (scope chain). 2796 } 2797 2798 if (mirror.isDate()) { 2799 // Add date specific properties. 2800 content.value = mirror.value(); 2801 } 2802 2803 if (mirror.isPromise()) { 2804 // Add promise specific properties. 2805 content.status = mirror.status(); 2806 content.promiseValue = this.serializeReference(mirror.promiseValue()); 2807 } 2808 2809 // Add actual properties - named properties followed by indexed properties. 2810 var properties = mirror.propertyNames(); 2811 for (var i = 0; i < properties.length; i++) { 2812 var propertyMirror = mirror.property(properties[i]); 2813 properties[i] = this.serializeProperty_(propertyMirror); 2814 if (details) { 2815 this.add_(propertyMirror.value()); 2816 } 2817 } 2818 content.properties = properties; 2819 2820 var internalProperties = mirror.internalProperties(); 2821 if (internalProperties.length > 0) { 2822 var ip = []; 2823 for (var i = 0; i < internalProperties.length; i++) { 2824 ip.push(this.serializeInternalProperty_(internalProperties[i])); 2825 } 2826 content.internalProperties = ip; 2827 } 2828}; 2829 2830 2831/** 2832 * Serialize location information to the following JSON format: 2833 * 2834 * "position":"<position>", 2835 * "line":"<line>", 2836 * "column":"<column>", 2837 * 2838 * @param {SourceLocation} location The location to serialize, may be undefined. 2839 */ 2840function serializeLocationFields (location, content) { 2841 if (!location) { 2842 return; 2843 } 2844 content.position = location.position; 2845 var line = location.line; 2846 if (!IS_UNDEFINED(line)) { 2847 content.line = line; 2848 } 2849 var column = location.column; 2850 if (!IS_UNDEFINED(column)) { 2851 content.column = column; 2852 } 2853} 2854 2855 2856/** 2857 * Serialize property information to the following JSON format for building the 2858 * array of properties. 2859 * 2860 * {"name":"<property name>", 2861 * "attributes":<number>, 2862 * "propertyType":<number>, 2863 * "ref":<number>} 2864 * 2865 * If the attribute for the property is PropertyAttribute.None it is not added. 2866 * Here are a couple of examples. 2867 * 2868 * {"name":"hello","propertyType":0,"ref":1} 2869 * {"name":"length","attributes":7,"propertyType":3,"ref":2} 2870 * 2871 * @param {PropertyMirror} propertyMirror The property to serialize. 2872 * @returns {Object} Protocol object representing the property. 2873 */ 2874JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) { 2875 var result = {}; 2876 2877 result.name = propertyMirror.name(); 2878 var propertyValue = propertyMirror.value(); 2879 if (this.inlineRefs_() && propertyValue.isValue()) { 2880 result.value = this.serializeReferenceWithDisplayData_(propertyValue); 2881 } else { 2882 if (propertyMirror.attributes() != PropertyAttribute.None) { 2883 result.attributes = propertyMirror.attributes(); 2884 } 2885 result.propertyType = propertyMirror.propertyType(); 2886 result.ref = propertyValue.handle(); 2887 } 2888 return result; 2889}; 2890 2891 2892/** 2893 * Serialize internal property information to the following JSON format for 2894 * building the array of properties. 2895 * 2896 * {"name":"<property name>", 2897 * "ref":<number>} 2898 * 2899 * {"name":"[[BoundThis]]","ref":117} 2900 * 2901 * @param {InternalPropertyMirror} propertyMirror The property to serialize. 2902 * @returns {Object} Protocol object representing the property. 2903 */ 2904JSONProtocolSerializer.prototype.serializeInternalProperty_ = 2905 function(propertyMirror) { 2906 var result = {}; 2907 2908 result.name = propertyMirror.name(); 2909 var propertyValue = propertyMirror.value(); 2910 if (this.inlineRefs_() && propertyValue.isValue()) { 2911 result.value = this.serializeReferenceWithDisplayData_(propertyValue); 2912 } else { 2913 result.ref = propertyValue.handle(); 2914 } 2915 return result; 2916}; 2917 2918 2919JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) { 2920 content.index = mirror.index(); 2921 content.receiver = this.serializeReference(mirror.receiver()); 2922 var func = mirror.func(); 2923 content.func = this.serializeReference(func); 2924 var script = func.script(); 2925 if (script) { 2926 content.script = this.serializeReference(script); 2927 } 2928 content.constructCall = mirror.isConstructCall(); 2929 content.atReturn = mirror.isAtReturn(); 2930 if (mirror.isAtReturn()) { 2931 content.returnValue = this.serializeReference(mirror.returnValue()); 2932 } 2933 content.debuggerFrame = mirror.isDebuggerFrame(); 2934 var x = new GlobalArray(mirror.argumentCount()); 2935 for (var i = 0; i < mirror.argumentCount(); i++) { 2936 var arg = {}; 2937 var argument_name = mirror.argumentName(i); 2938 if (argument_name) { 2939 arg.name = argument_name; 2940 } 2941 arg.value = this.serializeReference(mirror.argumentValue(i)); 2942 x[i] = arg; 2943 } 2944 content.arguments = x; 2945 var x = new GlobalArray(mirror.localCount()); 2946 for (var i = 0; i < mirror.localCount(); i++) { 2947 var local = {}; 2948 local.name = mirror.localName(i); 2949 local.value = this.serializeReference(mirror.localValue(i)); 2950 x[i] = local; 2951 } 2952 content.locals = x; 2953 serializeLocationFields(mirror.sourceLocation(), content); 2954 var source_line_text = mirror.sourceLineText(); 2955 if (!IS_UNDEFINED(source_line_text)) { 2956 content.sourceLineText = source_line_text; 2957 } 2958 2959 content.scopes = []; 2960 for (var i = 0; i < mirror.scopeCount(); i++) { 2961 var scope = mirror.scope(i); 2962 content.scopes.push({ 2963 type: scope.scopeType(), 2964 index: i 2965 }); 2966 } 2967}; 2968 2969 2970JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) { 2971 content.index = mirror.scopeIndex(); 2972 content.frameIndex = mirror.frameIndex(); 2973 content.type = mirror.scopeType(); 2974 content.object = this.inlineRefs_() ? 2975 this.serializeValue(mirror.scopeObject()) : 2976 this.serializeReference(mirror.scopeObject()); 2977}; 2978 2979 2980/** 2981 * Convert a number to a protocol value. For all finite numbers the number 2982 * itself is returned. For non finite numbers NaN, Infinite and 2983 * -Infinite the string representation "NaN", "Infinite" or "-Infinite" 2984 * (not including the quotes) is returned. 2985 * 2986 * @param {number} value The number value to convert to a protocol value. 2987 * @returns {number|string} Protocol value. 2988 */ 2989function NumberToJSON_(value) { 2990 if (IsNaN(value)) { 2991 return 'NaN'; 2992 } 2993 if (!NUMBER_IS_FINITE(value)) { 2994 if (value > 0) { 2995 return 'Infinity'; 2996 } else { 2997 return '-Infinity'; 2998 } 2999 } 3000 return value; 3001} 3002 3003// ---------------------------------------------------------------------------- 3004// Exports 3005 3006utils.InstallFunctions(global, DONT_ENUM, [ 3007 "MakeMirror", MakeMirror, 3008 "MakeMirrorSerializer", MakeMirrorSerializer, 3009 "LookupMirror", LookupMirror, 3010 "ToggleMirrorCache", ToggleMirrorCache, 3011 "MirrorCacheIsEmpty", MirrorCacheIsEmpty, 3012]); 3013 3014utils.InstallConstants(global, [ 3015 "ScopeType", ScopeType, 3016 "PropertyType", PropertyType, 3017 "PropertyAttribute", PropertyAttribute, 3018 "Mirror", Mirror, 3019 "ValueMirror", ValueMirror, 3020 "UndefinedMirror", UndefinedMirror, 3021 "NullMirror", NullMirror, 3022 "BooleanMirror", BooleanMirror, 3023 "NumberMirror", NumberMirror, 3024 "StringMirror", StringMirror, 3025 "SymbolMirror", SymbolMirror, 3026 "ObjectMirror", ObjectMirror, 3027 "FunctionMirror", FunctionMirror, 3028 "UnresolvedFunctionMirror", UnresolvedFunctionMirror, 3029 "ArrayMirror", ArrayMirror, 3030 "DateMirror", DateMirror, 3031 "RegExpMirror", RegExpMirror, 3032 "ErrorMirror", ErrorMirror, 3033 "PromiseMirror", PromiseMirror, 3034 "MapMirror", MapMirror, 3035 "SetMirror", SetMirror, 3036 "IteratorMirror", IteratorMirror, 3037 "GeneratorMirror", GeneratorMirror, 3038 "PropertyMirror", PropertyMirror, 3039 "InternalPropertyMirror", InternalPropertyMirror, 3040 "FrameMirror", FrameMirror, 3041 "ScriptMirror", ScriptMirror, 3042 "ScopeMirror", ScopeMirror, 3043 "FrameDetails", FrameDetails, 3044]); 3045 3046// Functions needed by the debugger runtime. 3047utils.InstallFunctions(utils, DONT_ENUM, [ 3048 "ClearMirrorCache", ClearMirrorCache 3049]); 3050 3051// Export to debug.js 3052utils.Export(function(to) { 3053 to.MirrorType = MirrorType; 3054}); 3055}) 3056