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