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