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