mirror-debugger.js revision 69a99ed0b2b2ef69d393c371b03db3a98aaf880e
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.
29var next_handle_ = 0;
30var next_transient_handle_ = -1;
31
32// Mirror cache.
33var mirror_cache_ = [];
34
35
36/**
37 * Clear the mirror handle cache.
38 */
39function 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 */
53function 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 */
109function 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 */
119function 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 */
137function 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.
147const UNDEFINED_TYPE = 'undefined';
148const NULL_TYPE = 'null';
149const BOOLEAN_TYPE = 'boolean';
150const NUMBER_TYPE = 'number';
151const STRING_TYPE = 'string';
152const OBJECT_TYPE = 'object';
153const FUNCTION_TYPE = 'function';
154const REGEXP_TYPE = 'regexp';
155const ERROR_TYPE = 'error';
156const PROPERTY_TYPE = 'property';
157const FRAME_TYPE = 'frame';
158const SCRIPT_TYPE = 'script';
159const CONTEXT_TYPE = 'context';
160const SCOPE_TYPE = 'scope';
161
162// Maximum length when sending strings through the JSON protocol.
163const kMaxProtocolStringLength = 80;
164
165// Different kind of properties.
166PropertyKind = {};
167PropertyKind.Named   = 1;
168PropertyKind.Indexed = 2;
169
170
171// A copy of the PropertyType enum from global.h
172PropertyType = {};
173PropertyType.Normal                  = 0;
174PropertyType.Field                   = 1;
175PropertyType.ConstantFunction        = 2;
176PropertyType.Callbacks               = 3;
177PropertyType.Handler                 = 4;
178PropertyType.Interceptor             = 5;
179PropertyType.MapTransition           = 6;
180PropertyType.ExternalArrayTransition = 7;
181PropertyType.ConstantTransition      = 8;
182PropertyType.NullDescriptor          = 9;
183
184
185// Different attributes for a property.
186PropertyAttribute = {};
187PropertyAttribute.None       = NONE;
188PropertyAttribute.ReadOnly   = READ_ONLY;
189PropertyAttribute.DontEnum   = DONT_ENUM;
190PropertyAttribute.DontDelete = DONT_DELETE;
191
192
193// A copy of the scope types from runtime.cc.
194ScopeType = { 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 */
226function Mirror(type) {
227  this.type_ = type;
228};
229
230
231Mirror.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 */
240Mirror.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 */
249Mirror.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 */
258Mirror.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 */
267Mirror.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 */
276Mirror.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 */
285Mirror.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 */
294Mirror.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 */
303Mirror.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 */
312Mirror.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 */
321Mirror.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 */
330Mirror.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 */
339Mirror.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 */
348Mirror.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 */
357Mirror.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 */
366Mirror.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 */
375Mirror.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 */
384Mirror.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 */
393Mirror.prototype.isScope = function() {
394  return this instanceof ScopeMirror;
395}
396
397
398/**
399 * Allocate a handle id for this object.
400 */
401Mirror.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 */
410Mirror.prototype.allocateTransientHandle_ = function() {
411  this.handle_ = next_transient_handle_--;
412}
413
414
415Mirror.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 */
430function 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}
439inherits(ValueMirror, Mirror);
440
441
442Mirror.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 */
451ValueMirror.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 */
465ValueMirror.prototype.value = function() {
466  return this.value_;
467};
468
469
470/**
471 * Mirror object for Undefined.
472 * @constructor
473 * @extends ValueMirror
474 */
475function UndefinedMirror() {
476  %_CallFunction(this, UNDEFINED_TYPE, void 0, ValueMirror);
477}
478inherits(UndefinedMirror, ValueMirror);
479
480
481UndefinedMirror.prototype.toText = function() {
482  return 'undefined';
483}
484
485
486/**
487 * Mirror object for null.
488 * @constructor
489 * @extends ValueMirror
490 */
491function NullMirror() {
492  %_CallFunction(this, NULL_TYPE, null, ValueMirror);
493}
494inherits(NullMirror, ValueMirror);
495
496
497NullMirror.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 */
508function BooleanMirror(value) {
509  %_CallFunction(this, BOOLEAN_TYPE, value, ValueMirror);
510}
511inherits(BooleanMirror, ValueMirror);
512
513
514BooleanMirror.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 */
525function NumberMirror(value) {
526  %_CallFunction(this, NUMBER_TYPE, value, ValueMirror);
527}
528inherits(NumberMirror, ValueMirror);
529
530
531NumberMirror.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 */
542function StringMirror(value) {
543  %_CallFunction(this, STRING_TYPE, value, ValueMirror);
544}
545inherits(StringMirror, ValueMirror);
546
547
548StringMirror.prototype.length = function() {
549  return this.value_.length;
550};
551
552StringMirror.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
560StringMirror.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 */
573function ObjectMirror(value, type, transient) {
574  %_CallFunction(this, type || OBJECT_TYPE, value, transient, ValueMirror);
575}
576inherits(ObjectMirror, ValueMirror);
577
578
579ObjectMirror.prototype.className = function() {
580  return %_ClassOf(this.value_);
581};
582
583
584ObjectMirror.prototype.constructorFunction = function() {
585  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
586};
587
588
589ObjectMirror.prototype.prototypeObject = function() {
590  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
591};
592
593
594ObjectMirror.prototype.protoObject = function() {
595  return MakeMirror(%DebugGetPrototype(this.value_));
596};
597
598
599ObjectMirror.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
606ObjectMirror.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 */
621ObjectMirror.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 */
693ObjectMirror.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
704ObjectMirror.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 */
722ObjectMirror.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 */
748ObjectMirror.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
762ObjectMirror.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 */
783function FunctionMirror(value) {
784  %_CallFunction(this, value, FUNCTION_TYPE, ObjectMirror);
785  this.resolved_ = true;
786}
787inherits(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 */
795FunctionMirror.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 */
804FunctionMirror.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 */
813FunctionMirror.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 */
823FunctionMirror.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 */
837FunctionMirror.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 */
854FunctionMirror.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 */
868FunctionMirror.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 */
882FunctionMirror.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
899FunctionMirror.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 */
911function 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}
919inherits(UnresolvedFunctionMirror, FunctionMirror);
920
921
922UnresolvedFunctionMirror.prototype.className = function() {
923  return 'Function';
924};
925
926
927UnresolvedFunctionMirror.prototype.constructorFunction = function() {
928  return GetUndefinedMirror();
929};
930
931
932UnresolvedFunctionMirror.prototype.prototypeObject = function() {
933  return GetUndefinedMirror();
934};
935
936
937UnresolvedFunctionMirror.prototype.protoObject = function() {
938  return GetUndefinedMirror();
939};
940
941
942UnresolvedFunctionMirror.prototype.name = function() {
943  return this.value_;
944};
945
946
947UnresolvedFunctionMirror.prototype.inferredName = function() {
948  return undefined;
949};
950
951
952UnresolvedFunctionMirror.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 */
963function ArrayMirror(value) {
964  %_CallFunction(this, value, ObjectMirror);
965}
966inherits(ArrayMirror, ObjectMirror);
967
968
969ArrayMirror.prototype.length = function() {
970  return this.value_.length;
971};
972
973
974ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) {
975  var from_index = opt_from_index || 0;
976  var to_index = opt_to_index || this.length() - 1;
977  if (from_index > to_index) return new Array();
978  var values = new Array(to_index - from_index + 1);
979  for (var i = from_index; i <= to_index; i++) {
980    var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
981    var value;
982    if (details) {
983      value = new PropertyMirror(this, i, details);
984    } else {
985      value = GetUndefinedMirror();
986    }
987    values[i - from_index] = value;
988  }
989  return values;
990}
991
992
993/**
994 * Mirror object for dates.
995 * @param {Date} value The Date object reflected by this mirror
996 * @constructor
997 * @extends ObjectMirror
998 */
999function DateMirror(value) {
1000  %_CallFunction(this, value, ObjectMirror);
1001}
1002inherits(DateMirror, ObjectMirror);
1003
1004
1005DateMirror.prototype.toText = function() {
1006  var s = JSON.stringify(this.value_);
1007  return s.substring(1, s.length - 1);  // cut quotes
1008}
1009
1010
1011/**
1012 * Mirror object for regular expressions.
1013 * @param {RegExp} value The RegExp object reflected by this mirror
1014 * @constructor
1015 * @extends ObjectMirror
1016 */
1017function RegExpMirror(value) {
1018  %_CallFunction(this, value, REGEXP_TYPE, ObjectMirror);
1019}
1020inherits(RegExpMirror, ObjectMirror);
1021
1022
1023/**
1024 * Returns the source to the regular expression.
1025 * @return {string or undefined} The source to the regular expression
1026 */
1027RegExpMirror.prototype.source = function() {
1028  return this.value_.source;
1029};
1030
1031
1032/**
1033 * Returns whether this regular expression has the global (g) flag set.
1034 * @return {boolean} Value of the global flag
1035 */
1036RegExpMirror.prototype.global = function() {
1037  return this.value_.global;
1038};
1039
1040
1041/**
1042 * Returns whether this regular expression has the ignore case (i) flag set.
1043 * @return {boolean} Value of the ignore case flag
1044 */
1045RegExpMirror.prototype.ignoreCase = function() {
1046  return this.value_.ignoreCase;
1047};
1048
1049
1050/**
1051 * Returns whether this regular expression has the multiline (m) flag set.
1052 * @return {boolean} Value of the multiline flag
1053 */
1054RegExpMirror.prototype.multiline = function() {
1055  return this.value_.multiline;
1056};
1057
1058
1059RegExpMirror.prototype.toText = function() {
1060  // Simpel to text which is used when on specialization in subclass.
1061  return "/" + this.source() + "/";
1062}
1063
1064
1065/**
1066 * Mirror object for error objects.
1067 * @param {Error} value The error object reflected by this mirror
1068 * @constructor
1069 * @extends ObjectMirror
1070 */
1071function ErrorMirror(value) {
1072  %_CallFunction(this, value, ERROR_TYPE, ObjectMirror);
1073}
1074inherits(ErrorMirror, ObjectMirror);
1075
1076
1077/**
1078 * Returns the message for this eror object.
1079 * @return {string or undefined} The message for this eror object
1080 */
1081ErrorMirror.prototype.message = function() {
1082  return this.value_.message;
1083};
1084
1085
1086ErrorMirror.prototype.toText = function() {
1087  // Use the same text representation as in messages.js.
1088  var text;
1089  try {
1090    str = %_CallFunction(this.value_, builtins.errorToString);
1091  } catch (e) {
1092    str = '#<Error>';
1093  }
1094  return str;
1095}
1096
1097
1098/**
1099 * Base mirror object for properties.
1100 * @param {ObjectMirror} mirror The mirror object having this property
1101 * @param {string} name The name of the property
1102 * @param {Array} details Details about the property
1103 * @constructor
1104 * @extends Mirror
1105 */
1106function PropertyMirror(mirror, name, details) {
1107  %_CallFunction(this, PROPERTY_TYPE, Mirror);
1108  this.mirror_ = mirror;
1109  this.name_ = name;
1110  this.value_ = details[0];
1111  this.details_ = details[1];
1112  if (details.length > 2) {
1113    this.exception_ = details[2]
1114    this.getter_ = details[3];
1115    this.setter_ = details[4];
1116  }
1117}
1118inherits(PropertyMirror, Mirror);
1119
1120
1121PropertyMirror.prototype.isReadOnly = function() {
1122  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
1123}
1124
1125
1126PropertyMirror.prototype.isEnum = function() {
1127  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
1128}
1129
1130
1131PropertyMirror.prototype.canDelete = function() {
1132  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
1133}
1134
1135
1136PropertyMirror.prototype.name = function() {
1137  return this.name_;
1138}
1139
1140
1141PropertyMirror.prototype.isIndexed = function() {
1142  for (var i = 0; i < this.name_.length; i++) {
1143    if (this.name_[i] < '0' || '9' < this.name_[i]) {
1144      return false;
1145    }
1146  }
1147  return true;
1148}
1149
1150
1151PropertyMirror.prototype.value = function() {
1152  return MakeMirror(this.value_, false);
1153}
1154
1155
1156/**
1157 * Returns whether this property value is an exception.
1158 * @return {booolean} True if this property value is an exception
1159 */
1160PropertyMirror.prototype.isException = function() {
1161  return this.exception_ ? true : false;
1162}
1163
1164
1165PropertyMirror.prototype.attributes = function() {
1166  return %DebugPropertyAttributesFromDetails(this.details_);
1167}
1168
1169
1170PropertyMirror.prototype.propertyType = function() {
1171  return %DebugPropertyTypeFromDetails(this.details_);
1172}
1173
1174
1175PropertyMirror.prototype.insertionIndex = function() {
1176  return %DebugPropertyIndexFromDetails(this.details_);
1177}
1178
1179
1180/**
1181 * Returns whether this property has a getter defined through __defineGetter__.
1182 * @return {booolean} True if this property has a getter
1183 */
1184PropertyMirror.prototype.hasGetter = function() {
1185  return this.getter_ ? true : false;
1186}
1187
1188
1189/**
1190 * Returns whether this property has a setter defined through __defineSetter__.
1191 * @return {booolean} True if this property has a setter
1192 */
1193PropertyMirror.prototype.hasSetter = function() {
1194  return this.setter_ ? true : false;
1195}
1196
1197
1198/**
1199 * Returns the getter for this property defined through __defineGetter__.
1200 * @return {Mirror} FunctionMirror reflecting the getter function or
1201 *     UndefinedMirror if there is no getter for this property
1202 */
1203PropertyMirror.prototype.getter = function() {
1204  if (this.hasGetter()) {
1205    return MakeMirror(this.getter_);
1206  } else {
1207    return GetUndefinedMirror();
1208  }
1209}
1210
1211
1212/**
1213 * Returns the setter for this property defined through __defineSetter__.
1214 * @return {Mirror} FunctionMirror reflecting the setter function or
1215 *     UndefinedMirror if there is no setter for this property
1216 */
1217PropertyMirror.prototype.setter = function() {
1218  if (this.hasSetter()) {
1219    return MakeMirror(this.setter_);
1220  } else {
1221    return GetUndefinedMirror();
1222  }
1223}
1224
1225
1226/**
1227 * Returns whether this property is natively implemented by the host or a set
1228 * through JavaScript code.
1229 * @return {boolean} True if the property is
1230 *     UndefinedMirror if there is no setter for this property
1231 */
1232PropertyMirror.prototype.isNative = function() {
1233  return (this.propertyType() == PropertyType.Interceptor) ||
1234         ((this.propertyType() == PropertyType.Callbacks) &&
1235          !this.hasGetter() && !this.hasSetter());
1236}
1237
1238
1239const kFrameDetailsFrameIdIndex = 0;
1240const kFrameDetailsReceiverIndex = 1;
1241const kFrameDetailsFunctionIndex = 2;
1242const kFrameDetailsArgumentCountIndex = 3;
1243const kFrameDetailsLocalCountIndex = 4;
1244const kFrameDetailsSourcePositionIndex = 5;
1245const kFrameDetailsConstructCallIndex = 6;
1246const kFrameDetailsAtReturnIndex = 7;
1247const kFrameDetailsFlagsIndex = 8;
1248const kFrameDetailsFirstDynamicIndex = 9;
1249
1250const kFrameDetailsNameIndex = 0;
1251const kFrameDetailsValueIndex = 1;
1252const kFrameDetailsNameValueSize = 2;
1253
1254const kFrameDetailsFlagDebuggerFrameMask = 1 << 0;
1255const kFrameDetailsFlagOptimizedFrameMask = 1 << 1;
1256const kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2;
1257
1258/**
1259 * Wrapper for the frame details information retreived from the VM. The frame
1260 * details from the VM is an array with the following content. See runtime.cc
1261 * Runtime_GetFrameDetails.
1262 *     0: Id
1263 *     1: Receiver
1264 *     2: Function
1265 *     3: Argument count
1266 *     4: Local count
1267 *     5: Source position
1268 *     6: Construct call
1269 *     7: Is at return
1270 *     8: Flags (debugger frame, optimized frame, inlined frame index)
1271 *     Arguments name, value
1272 *     Locals name, value
1273 *     Return value if any
1274 * @param {number} break_id Current break id
1275 * @param {number} index Frame number
1276 * @constructor
1277 */
1278function FrameDetails(break_id, index) {
1279  this.break_id_ = break_id;
1280  this.details_ = %GetFrameDetails(break_id, index);
1281}
1282
1283
1284FrameDetails.prototype.frameId = function() {
1285  %CheckExecutionState(this.break_id_);
1286  return this.details_[kFrameDetailsFrameIdIndex];
1287}
1288
1289
1290FrameDetails.prototype.receiver = function() {
1291  %CheckExecutionState(this.break_id_);
1292  return this.details_[kFrameDetailsReceiverIndex];
1293}
1294
1295
1296FrameDetails.prototype.func = function() {
1297  %CheckExecutionState(this.break_id_);
1298  return this.details_[kFrameDetailsFunctionIndex];
1299}
1300
1301
1302FrameDetails.prototype.isConstructCall = function() {
1303  %CheckExecutionState(this.break_id_);
1304  return this.details_[kFrameDetailsConstructCallIndex];
1305}
1306
1307
1308FrameDetails.prototype.isAtReturn = function() {
1309  %CheckExecutionState(this.break_id_);
1310  return this.details_[kFrameDetailsAtReturnIndex];
1311}
1312
1313
1314FrameDetails.prototype.isDebuggerFrame = function() {
1315  %CheckExecutionState(this.break_id_);
1316  var f = kFrameDetailsFlagDebuggerFrameMask;
1317  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
1318}
1319
1320
1321FrameDetails.prototype.isOptimizedFrame = function() {
1322  %CheckExecutionState(this.break_id_);
1323  var f = kFrameDetailsFlagOptimizedFrameMask;
1324  return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
1325}
1326
1327
1328FrameDetails.prototype.isInlinedFrame = function() {
1329  return this.inlinedFrameIndex() > 0;
1330}
1331
1332
1333FrameDetails.prototype.inlinedFrameIndex = function() {
1334  %CheckExecutionState(this.break_id_);
1335  var f = kFrameDetailsFlagInlinedFrameIndexMask;
1336  return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2
1337}
1338
1339
1340FrameDetails.prototype.argumentCount = function() {
1341  %CheckExecutionState(this.break_id_);
1342  return this.details_[kFrameDetailsArgumentCountIndex];
1343}
1344
1345
1346FrameDetails.prototype.argumentName = function(index) {
1347  %CheckExecutionState(this.break_id_);
1348  if (index >= 0 && index < this.argumentCount()) {
1349    return this.details_[kFrameDetailsFirstDynamicIndex +
1350                         index * kFrameDetailsNameValueSize +
1351                         kFrameDetailsNameIndex]
1352  }
1353}
1354
1355
1356FrameDetails.prototype.argumentValue = function(index) {
1357  %CheckExecutionState(this.break_id_);
1358  if (index >= 0 && index < this.argumentCount()) {
1359    return this.details_[kFrameDetailsFirstDynamicIndex +
1360                         index * kFrameDetailsNameValueSize +
1361                         kFrameDetailsValueIndex]
1362  }
1363}
1364
1365
1366FrameDetails.prototype.localCount = function() {
1367  %CheckExecutionState(this.break_id_);
1368  return this.details_[kFrameDetailsLocalCountIndex];
1369}
1370
1371
1372FrameDetails.prototype.sourcePosition = function() {
1373  %CheckExecutionState(this.break_id_);
1374  return this.details_[kFrameDetailsSourcePositionIndex];
1375}
1376
1377
1378FrameDetails.prototype.localName = function(index) {
1379  %CheckExecutionState(this.break_id_);
1380  if (index >= 0 && index < this.localCount()) {
1381    var locals_offset = kFrameDetailsFirstDynamicIndex +
1382                        this.argumentCount() * kFrameDetailsNameValueSize
1383    return this.details_[locals_offset +
1384                         index * kFrameDetailsNameValueSize +
1385                         kFrameDetailsNameIndex]
1386  }
1387}
1388
1389
1390FrameDetails.prototype.localValue = function(index) {
1391  %CheckExecutionState(this.break_id_);
1392  if (index >= 0 && index < this.localCount()) {
1393    var locals_offset = kFrameDetailsFirstDynamicIndex +
1394                        this.argumentCount() * kFrameDetailsNameValueSize
1395    return this.details_[locals_offset +
1396                         index * kFrameDetailsNameValueSize +
1397                         kFrameDetailsValueIndex]
1398  }
1399}
1400
1401
1402FrameDetails.prototype.returnValue = function() {
1403  %CheckExecutionState(this.break_id_);
1404  var return_value_offset =
1405      kFrameDetailsFirstDynamicIndex +
1406      (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize;
1407  if (this.details_[kFrameDetailsAtReturnIndex]) {
1408    return this.details_[return_value_offset];
1409  }
1410}
1411
1412
1413FrameDetails.prototype.scopeCount = function() {
1414  return %GetScopeCount(this.break_id_, this.frameId());
1415}
1416
1417
1418/**
1419 * Mirror object for stack frames.
1420 * @param {number} break_id The break id in the VM for which this frame is
1421       valid
1422 * @param {number} index The frame index (top frame is index 0)
1423 * @constructor
1424 * @extends Mirror
1425 */
1426function FrameMirror(break_id, index) {
1427  %_CallFunction(this, FRAME_TYPE, Mirror);
1428  this.break_id_ = break_id;
1429  this.index_ = index;
1430  this.details_ = new FrameDetails(break_id, index);
1431}
1432inherits(FrameMirror, Mirror);
1433
1434
1435FrameMirror.prototype.index = function() {
1436  return this.index_;
1437};
1438
1439
1440FrameMirror.prototype.func = function() {
1441  // Get the function for this frame from the VM.
1442  var f = this.details_.func();
1443
1444  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1445  // value returned from the VM might be a string if the function for the
1446  // frame is unresolved.
1447  if (IS_FUNCTION(f)) {
1448    return MakeMirror(f);
1449  } else {
1450    return new UnresolvedFunctionMirror(f);
1451  }
1452};
1453
1454
1455FrameMirror.prototype.receiver = function() {
1456  return MakeMirror(this.details_.receiver());
1457};
1458
1459
1460FrameMirror.prototype.isConstructCall = function() {
1461  return this.details_.isConstructCall();
1462};
1463
1464
1465FrameMirror.prototype.isAtReturn = function() {
1466  return this.details_.isAtReturn();
1467};
1468
1469
1470FrameMirror.prototype.isDebuggerFrame = function() {
1471  return this.details_.isDebuggerFrame();
1472};
1473
1474
1475FrameMirror.prototype.isOptimizedFrame = function() {
1476  return this.details_.isOptimizedFrame();
1477};
1478
1479
1480FrameMirror.prototype.isInlinedFrame = function() {
1481  return this.details_.isInlinedFrame();
1482};
1483
1484
1485FrameMirror.prototype.inlinedFrameIndex = function() {
1486  return this.details_.inlinedFrameIndex();
1487};
1488
1489
1490FrameMirror.prototype.argumentCount = function() {
1491  return this.details_.argumentCount();
1492};
1493
1494
1495FrameMirror.prototype.argumentName = function(index) {
1496  return this.details_.argumentName(index);
1497};
1498
1499
1500FrameMirror.prototype.argumentValue = function(index) {
1501  return MakeMirror(this.details_.argumentValue(index));
1502};
1503
1504
1505FrameMirror.prototype.localCount = function() {
1506  return this.details_.localCount();
1507};
1508
1509
1510FrameMirror.prototype.localName = function(index) {
1511  return this.details_.localName(index);
1512};
1513
1514
1515FrameMirror.prototype.localValue = function(index) {
1516  return MakeMirror(this.details_.localValue(index));
1517};
1518
1519
1520FrameMirror.prototype.returnValue = function() {
1521  return MakeMirror(this.details_.returnValue());
1522};
1523
1524
1525FrameMirror.prototype.sourcePosition = function() {
1526  return this.details_.sourcePosition();
1527};
1528
1529
1530FrameMirror.prototype.sourceLocation = function() {
1531  if (this.func().resolved() && this.func().script()) {
1532    return this.func().script().locationFromPosition(this.sourcePosition(),
1533                                                     true);
1534  }
1535};
1536
1537
1538FrameMirror.prototype.sourceLine = function() {
1539  if (this.func().resolved()) {
1540    var location = this.sourceLocation();
1541    if (location) {
1542      return location.line;
1543    }
1544  }
1545};
1546
1547
1548FrameMirror.prototype.sourceColumn = function() {
1549  if (this.func().resolved()) {
1550    var location = this.sourceLocation();
1551    if (location) {
1552      return location.column;
1553    }
1554  }
1555};
1556
1557
1558FrameMirror.prototype.sourceLineText = function() {
1559  if (this.func().resolved()) {
1560    var location = this.sourceLocation();
1561    if (location) {
1562      return location.sourceText();
1563    }
1564  }
1565};
1566
1567
1568FrameMirror.prototype.scopeCount = function() {
1569  return this.details_.scopeCount();
1570};
1571
1572
1573FrameMirror.prototype.scope = function(index) {
1574  return new ScopeMirror(this, index);
1575};
1576
1577
1578FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) {
1579  var result = %DebugEvaluate(this.break_id_,
1580                              this.details_.frameId(),
1581                              this.details_.inlinedFrameIndex(),
1582                              source,
1583                              Boolean(disable_break),
1584                              opt_context_object);
1585  return MakeMirror(result);
1586};
1587
1588
1589FrameMirror.prototype.invocationText = function() {
1590  // Format frame invoaction (receiver, function and arguments).
1591  var result = '';
1592  var func = this.func();
1593  var receiver = this.receiver();
1594  if (this.isConstructCall()) {
1595    // For constructor frames display new followed by the function name.
1596    result += 'new ';
1597    result += func.name() ? func.name() : '[anonymous]';
1598  } else if (this.isDebuggerFrame()) {
1599    result += '[debugger]';
1600  } else {
1601    // If the receiver has a className which is 'global' don't display it.
1602    var display_receiver = !receiver.className || receiver.className() != 'global';
1603    if (display_receiver) {
1604      result += receiver.toText();
1605    }
1606    // Try to find the function as a property in the receiver. Include the
1607    // prototype chain in the lookup.
1608    var property = GetUndefinedMirror();
1609    if (receiver.isObject()) {
1610      for (var r = receiver;
1611           !r.isNull() && property.isUndefined();
1612           r = r.protoObject()) {
1613        property = r.lookupProperty(func);
1614      }
1615    }
1616    if (!property.isUndefined()) {
1617      // The function invoked was found on the receiver. Use the property name
1618      // for the backtrace.
1619      if (!property.isIndexed()) {
1620        if (display_receiver) {
1621          result += '.';
1622        }
1623        result += property.name();
1624      } else {
1625        result += '[';
1626        result += property.name();
1627        result += ']';
1628      }
1629      // Also known as - if the name in the function doesn't match the name
1630      // under which it was looked up.
1631      if (func.name() && func.name() != property.name()) {
1632        result += '(aka ' + func.name() + ')';
1633      }
1634    } else {
1635      // The function invoked was not found on the receiver. Use the function
1636      // name if available for the backtrace.
1637      if (display_receiver) {
1638        result += '.';
1639      }
1640      result += func.name() ? func.name() : '[anonymous]';
1641    }
1642  }
1643
1644  // Render arguments for normal frames.
1645  if (!this.isDebuggerFrame()) {
1646    result += '(';
1647    for (var i = 0; i < this.argumentCount(); i++) {
1648      if (i != 0) result += ', ';
1649      if (this.argumentName(i)) {
1650        result += this.argumentName(i);
1651        result += '=';
1652      }
1653      result += this.argumentValue(i).toText();
1654    }
1655    result += ')';
1656  }
1657
1658  if (this.isAtReturn()) {
1659    result += ' returning ';
1660    result += this.returnValue().toText();
1661  }
1662
1663  return result;
1664}
1665
1666
1667FrameMirror.prototype.sourceAndPositionText = function() {
1668  // Format source and position.
1669  var result = '';
1670  var func = this.func();
1671  if (func.resolved()) {
1672    if (func.script()) {
1673      if (func.script().name()) {
1674        result += func.script().name();
1675      } else {
1676        result += '[unnamed]';
1677      }
1678      if (!this.isDebuggerFrame()) {
1679        var location = this.sourceLocation();
1680        result += ' line ';
1681        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1682        result += ' column ';
1683        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1684        if (!IS_UNDEFINED(this.sourcePosition())) {
1685          result += ' (position ' + (this.sourcePosition() + 1) + ')';
1686        }
1687      }
1688    } else {
1689      result += '[no source]';
1690    }
1691  } else {
1692    result += '[unresolved]';
1693  }
1694
1695  return result;
1696}
1697
1698
1699FrameMirror.prototype.localsText = function() {
1700  // Format local variables.
1701  var result = '';
1702  var locals_count = this.localCount()
1703  if (locals_count > 0) {
1704    for (var i = 0; i < locals_count; ++i) {
1705      result += '      var ';
1706      result += this.localName(i);
1707      result += ' = ';
1708      result += this.localValue(i).toText();
1709      if (i < locals_count - 1) result += '\n';
1710    }
1711  }
1712
1713  return result;
1714}
1715
1716
1717FrameMirror.prototype.toText = function(opt_locals) {
1718  var result = '';
1719  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1720  result += ' ';
1721  result += this.invocationText();
1722  result += ' ';
1723  result += this.sourceAndPositionText();
1724  if (opt_locals) {
1725    result += '\n';
1726    result += this.localsText();
1727  }
1728  return result;
1729}
1730
1731
1732const kScopeDetailsTypeIndex = 0;
1733const kScopeDetailsObjectIndex = 1;
1734
1735function ScopeDetails(frame, index) {
1736  this.break_id_ = frame.break_id_;
1737  this.details_ = %GetScopeDetails(frame.break_id_,
1738                                   frame.details_.frameId(),
1739                                   frame.details_.inlinedFrameIndex(),
1740                                   index);
1741}
1742
1743
1744ScopeDetails.prototype.type = function() {
1745  %CheckExecutionState(this.break_id_);
1746  return this.details_[kScopeDetailsTypeIndex];
1747}
1748
1749
1750ScopeDetails.prototype.object = function() {
1751  %CheckExecutionState(this.break_id_);
1752  return this.details_[kScopeDetailsObjectIndex];
1753}
1754
1755
1756/**
1757 * Mirror object for scope.
1758 * @param {FrameMirror} frame The frame this scope is a part of
1759 * @param {number} index The scope index in the frame
1760 * @constructor
1761 * @extends Mirror
1762 */
1763function ScopeMirror(frame, index) {
1764  %_CallFunction(this, SCOPE_TYPE, Mirror);
1765  this.frame_index_ = frame.index_;
1766  this.scope_index_ = index;
1767  this.details_ = new ScopeDetails(frame, index);
1768}
1769inherits(ScopeMirror, Mirror);
1770
1771
1772ScopeMirror.prototype.frameIndex = function() {
1773  return this.frame_index_;
1774};
1775
1776
1777ScopeMirror.prototype.scopeIndex = function() {
1778  return this.scope_index_;
1779};
1780
1781
1782ScopeMirror.prototype.scopeType = function() {
1783  return this.details_.type();
1784};
1785
1786
1787ScopeMirror.prototype.scopeObject = function() {
1788  // For local and closure scopes create a transient mirror as these objects are
1789  // created on the fly materializing the local or closure scopes and
1790  // therefore will not preserve identity.
1791  var transient = this.scopeType() == ScopeType.Local ||
1792                  this.scopeType() == ScopeType.Closure;
1793  return MakeMirror(this.details_.object(), transient);
1794};
1795
1796
1797/**
1798 * Mirror object for script source.
1799 * @param {Script} script The script object
1800 * @constructor
1801 * @extends Mirror
1802 */
1803function ScriptMirror(script) {
1804  %_CallFunction(this, SCRIPT_TYPE, Mirror);
1805  this.script_ = script;
1806  this.context_ = new ContextMirror(script.context_data);
1807  this.allocateHandle_();
1808}
1809inherits(ScriptMirror, Mirror);
1810
1811
1812ScriptMirror.prototype.value = function() {
1813  return this.script_;
1814};
1815
1816
1817ScriptMirror.prototype.name = function() {
1818  return this.script_.name || this.script_.nameOrSourceURL();
1819};
1820
1821
1822ScriptMirror.prototype.id = function() {
1823  return this.script_.id;
1824};
1825
1826
1827ScriptMirror.prototype.source = function() {
1828  return this.script_.source;
1829};
1830
1831
1832ScriptMirror.prototype.lineOffset = function() {
1833  return this.script_.line_offset;
1834};
1835
1836
1837ScriptMirror.prototype.columnOffset = function() {
1838  return this.script_.column_offset;
1839};
1840
1841
1842ScriptMirror.prototype.data = function() {
1843  return this.script_.data;
1844};
1845
1846
1847ScriptMirror.prototype.scriptType = function() {
1848  return this.script_.type;
1849};
1850
1851
1852ScriptMirror.prototype.compilationType = function() {
1853  return this.script_.compilation_type;
1854};
1855
1856
1857ScriptMirror.prototype.lineCount = function() {
1858  return this.script_.lineCount();
1859};
1860
1861
1862ScriptMirror.prototype.locationFromPosition = function(
1863    position, include_resource_offset) {
1864  return this.script_.locationFromPosition(position, include_resource_offset);
1865}
1866
1867
1868ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1869  return this.script_.sourceSlice(opt_from_line, opt_to_line);
1870}
1871
1872
1873ScriptMirror.prototype.context = function() {
1874  return this.context_;
1875};
1876
1877
1878ScriptMirror.prototype.evalFromScript = function() {
1879  return MakeMirror(this.script_.eval_from_script);
1880};
1881
1882
1883ScriptMirror.prototype.evalFromFunctionName = function() {
1884  return MakeMirror(this.script_.eval_from_function_name);
1885};
1886
1887
1888ScriptMirror.prototype.evalFromLocation = function() {
1889  var eval_from_script = this.evalFromScript();
1890  if (!eval_from_script.isUndefined()) {
1891    var position = this.script_.eval_from_script_position;
1892    return eval_from_script.locationFromPosition(position, true);
1893  }
1894};
1895
1896
1897ScriptMirror.prototype.toText = function() {
1898  var result = '';
1899  result += this.name();
1900  result += ' (lines: ';
1901  if (this.lineOffset() > 0) {
1902    result += this.lineOffset();
1903    result += '-';
1904    result += this.lineOffset() + this.lineCount() - 1;
1905  } else {
1906    result += this.lineCount();
1907  }
1908  result += ')';
1909  return result;
1910}
1911
1912
1913/**
1914 * Mirror object for context.
1915 * @param {Object} data The context data
1916 * @constructor
1917 * @extends Mirror
1918 */
1919function ContextMirror(data) {
1920  %_CallFunction(this, CONTEXT_TYPE, Mirror);
1921  this.data_ = data;
1922  this.allocateHandle_();
1923}
1924inherits(ContextMirror, Mirror);
1925
1926
1927ContextMirror.prototype.data = function() {
1928  return this.data_;
1929};
1930
1931
1932/**
1933 * Returns a mirror serializer
1934 *
1935 * @param {boolean} details Set to true to include details
1936 * @param {Object} options Options comtrolling the serialization
1937 *     The following options can be set:
1938 *       includeSource: include ths full source of scripts
1939 * @returns {MirrorSerializer} mirror serializer
1940 */
1941function MakeMirrorSerializer(details, options) {
1942  return new JSONProtocolSerializer(details, options);
1943}
1944
1945
1946/**
1947 * Object for serializing a mirror objects and its direct references.
1948 * @param {boolean} details Indicates whether to include details for the mirror
1949 *     serialized
1950 * @constructor
1951 */
1952function JSONProtocolSerializer(details, options) {
1953  this.details_ = details;
1954  this.options_ = options;
1955  this.mirrors_ = [ ];
1956}
1957
1958
1959/**
1960 * Returns a serialization of an object reference. The referenced object are
1961 * added to the serialization state.
1962 *
1963 * @param {Mirror} mirror The mirror to serialize
1964 * @returns {String} JSON serialization
1965 */
1966JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1967  return this.serialize_(mirror, true, true);
1968}
1969
1970
1971/**
1972 * Returns a serialization of an object value. The referenced objects are
1973 * added to the serialization state.
1974 *
1975 * @param {Mirror} mirror The mirror to serialize
1976 * @returns {String} JSON serialization
1977 */
1978JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1979  var json = this.serialize_(mirror, false, true);
1980  return json;
1981}
1982
1983
1984/**
1985 * Returns a serialization of all the objects referenced.
1986 *
1987 * @param {Mirror} mirror The mirror to serialize.
1988 * @returns {Array.<Object>} Array of the referenced objects converted to
1989 *     protcol objects.
1990 */
1991JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
1992  // Collect the protocol representation of the referenced objects in an array.
1993  var content = [];
1994
1995  // Get the number of referenced objects.
1996  var count = this.mirrors_.length;
1997
1998  for (var i = 0; i < count; i++) {
1999    content.push(this.serialize_(this.mirrors_[i], false, false));
2000  }
2001
2002  return content;
2003}
2004
2005
2006JSONProtocolSerializer.prototype.includeSource_ = function() {
2007  return this.options_ && this.options_.includeSource;
2008}
2009
2010
2011JSONProtocolSerializer.prototype.inlineRefs_ = function() {
2012  return this.options_ && this.options_.inlineRefs;
2013}
2014
2015
2016JSONProtocolSerializer.prototype.maxStringLength_ = function() {
2017  if (IS_UNDEFINED(this.options_) ||
2018      IS_UNDEFINED(this.options_.maxStringLength)) {
2019    return kMaxProtocolStringLength;
2020  }
2021  return this.options_.maxStringLength;
2022}
2023
2024
2025JSONProtocolSerializer.prototype.add_ = function(mirror) {
2026  // If this mirror is already in the list just return.
2027  for (var i = 0; i < this.mirrors_.length; i++) {
2028    if (this.mirrors_[i] === mirror) {
2029      return;
2030    }
2031  }
2032
2033  // Add the mirror to the list of mirrors to be serialized.
2034  this.mirrors_.push(mirror);
2035}
2036
2037
2038/**
2039 * Formats mirror object to protocol reference object with some data that can
2040 * be used to display the value in debugger.
2041 * @param {Mirror} mirror Mirror to serialize.
2042 * @return {Object} Protocol reference object.
2043 */
2044JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
2045    function(mirror) {
2046  var o = {};
2047  o.ref = mirror.handle();
2048  o.type = mirror.type();
2049  switch (mirror.type()) {
2050    case UNDEFINED_TYPE:
2051    case NULL_TYPE:
2052    case BOOLEAN_TYPE:
2053    case NUMBER_TYPE:
2054      o.value = mirror.value();
2055      break;
2056    case STRING_TYPE:
2057      o.value = mirror.getTruncatedValue(this.maxStringLength_());
2058      break;
2059    case FUNCTION_TYPE:
2060      o.name = mirror.name();
2061      o.inferredName = mirror.inferredName();
2062      if (mirror.script()) {
2063        o.scriptId = mirror.script().id();
2064      }
2065      break;
2066    case ERROR_TYPE:
2067    case REGEXP_TYPE:
2068      o.value = mirror.toText();
2069      break;
2070    case OBJECT_TYPE:
2071      o.className = mirror.className();
2072      break;
2073  }
2074  return o;
2075};
2076
2077
2078JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
2079                                                       details) {
2080  // If serializing a reference to a mirror just return the reference and add
2081  // the mirror to the referenced mirrors.
2082  if (reference &&
2083      (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
2084    if (this.inlineRefs_() && mirror.isValue()) {
2085      return this.serializeReferenceWithDisplayData_(mirror);
2086    } else {
2087      this.add_(mirror);
2088      return {'ref' : mirror.handle()};
2089    }
2090  }
2091
2092  // Collect the JSON property/value pairs.
2093  var content = {};
2094
2095  // Add the mirror handle.
2096  if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
2097    content.handle = mirror.handle();
2098  }
2099
2100  // Always add the type.
2101  content.type = mirror.type();
2102
2103  switch (mirror.type()) {
2104    case UNDEFINED_TYPE:
2105    case NULL_TYPE:
2106      // Undefined and null are represented just by their type.
2107      break;
2108
2109    case BOOLEAN_TYPE:
2110      // Boolean values are simply represented by their value.
2111      content.value = mirror.value();
2112      break;
2113
2114    case NUMBER_TYPE:
2115      // Number values are simply represented by their value.
2116      content.value = NumberToJSON_(mirror.value());
2117      break;
2118
2119    case STRING_TYPE:
2120      // String values might have their value cropped to keep down size.
2121      if (this.maxStringLength_() != -1 &&
2122          mirror.length() > this.maxStringLength_()) {
2123        var str = mirror.getTruncatedValue(this.maxStringLength_());
2124        content.value = str;
2125        content.fromIndex = 0;
2126        content.toIndex = this.maxStringLength_();
2127      } else {
2128        content.value = mirror.value();
2129      }
2130      content.length = mirror.length();
2131      break;
2132
2133    case OBJECT_TYPE:
2134    case FUNCTION_TYPE:
2135    case ERROR_TYPE:
2136    case REGEXP_TYPE:
2137      // Add object representation.
2138      this.serializeObject_(mirror, content, details);
2139      break;
2140
2141    case PROPERTY_TYPE:
2142      throw new Error('PropertyMirror cannot be serialized independeltly')
2143      break;
2144
2145    case FRAME_TYPE:
2146      // Add object representation.
2147      this.serializeFrame_(mirror, content);
2148      break;
2149
2150    case SCOPE_TYPE:
2151      // Add object representation.
2152      this.serializeScope_(mirror, content);
2153      break;
2154
2155    case SCRIPT_TYPE:
2156      // Script is represented by id, name and source attributes.
2157      if (mirror.name()) {
2158        content.name = mirror.name();
2159      }
2160      content.id = mirror.id();
2161      content.lineOffset = mirror.lineOffset();
2162      content.columnOffset = mirror.columnOffset();
2163      content.lineCount = mirror.lineCount();
2164      if (mirror.data()) {
2165        content.data = mirror.data();
2166      }
2167      if (this.includeSource_()) {
2168        content.source = mirror.source();
2169      } else {
2170        var sourceStart = mirror.source().substring(0, 80);
2171        content.sourceStart = sourceStart;
2172      }
2173      content.sourceLength = mirror.source().length;
2174      content.scriptType = mirror.scriptType();
2175      content.compilationType = mirror.compilationType();
2176      // For compilation type eval emit information on the script from which
2177      // eval was called if a script is present.
2178      if (mirror.compilationType() == 1 &&
2179          mirror.evalFromScript()) {
2180        content.evalFromScript =
2181            this.serializeReference(mirror.evalFromScript());
2182        var evalFromLocation = mirror.evalFromLocation()
2183        if (evalFromLocation) {
2184          content.evalFromLocation = { line: evalFromLocation.line,
2185                                       column: evalFromLocation.column };
2186        }
2187        if (mirror.evalFromFunctionName()) {
2188          content.evalFromFunctionName = mirror.evalFromFunctionName();
2189        }
2190      }
2191      if (mirror.context()) {
2192        content.context = this.serializeReference(mirror.context());
2193      }
2194      break;
2195
2196    case CONTEXT_TYPE:
2197      content.data = mirror.data();
2198      break;
2199  }
2200
2201  // Always add the text representation.
2202  content.text = mirror.toText();
2203
2204  // Create and return the JSON string.
2205  return content;
2206}
2207
2208
2209/**
2210 * Serialize object information to the following JSON format.
2211 *
2212 *   {"className":"<class name>",
2213 *    "constructorFunction":{"ref":<number>},
2214 *    "protoObject":{"ref":<number>},
2215 *    "prototypeObject":{"ref":<number>},
2216 *    "namedInterceptor":<boolean>,
2217 *    "indexedInterceptor":<boolean>,
2218 *    "properties":[<properties>]}
2219 */
2220JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
2221                                                             details) {
2222  // Add general object properties.
2223  content.className = mirror.className();
2224  content.constructorFunction =
2225      this.serializeReference(mirror.constructorFunction());
2226  content.protoObject = this.serializeReference(mirror.protoObject());
2227  content.prototypeObject = this.serializeReference(mirror.prototypeObject());
2228
2229  // Add flags to indicate whether there are interceptors.
2230  if (mirror.hasNamedInterceptor()) {
2231    content.namedInterceptor = true;
2232  }
2233  if (mirror.hasIndexedInterceptor()) {
2234    content.indexedInterceptor = true;
2235  }
2236
2237  // Add function specific properties.
2238  if (mirror.isFunction()) {
2239    // Add function specific properties.
2240    content.name = mirror.name();
2241    if (!IS_UNDEFINED(mirror.inferredName())) {
2242      content.inferredName = mirror.inferredName();
2243    }
2244    content.resolved = mirror.resolved();
2245    if (mirror.resolved()) {
2246      content.source = mirror.source();
2247    }
2248    if (mirror.script()) {
2249      content.script = this.serializeReference(mirror.script());
2250      content.scriptId = mirror.script().id();
2251
2252      serializeLocationFields(mirror.sourceLocation(), content);
2253    }
2254  }
2255
2256  // Add date specific properties.
2257  if (mirror.isDate()) {
2258    // Add date specific properties.
2259    content.value = mirror.value();
2260  }
2261
2262  // Add actual properties - named properties followed by indexed properties.
2263  var propertyNames = mirror.propertyNames(PropertyKind.Named);
2264  var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
2265  var p = new Array(propertyNames.length + propertyIndexes.length);
2266  for (var i = 0; i < propertyNames.length; i++) {
2267    var propertyMirror = mirror.property(propertyNames[i]);
2268    p[i] = this.serializeProperty_(propertyMirror);
2269    if (details) {
2270      this.add_(propertyMirror.value());
2271    }
2272  }
2273  for (var i = 0; i < propertyIndexes.length; i++) {
2274    var propertyMirror = mirror.property(propertyIndexes[i]);
2275    p[propertyNames.length + i] = this.serializeProperty_(propertyMirror);
2276    if (details) {
2277      this.add_(propertyMirror.value());
2278    }
2279  }
2280  content.properties = p;
2281}
2282
2283
2284/**
2285 * Serialize location information to the following JSON format:
2286 *
2287 *   "position":"<position>",
2288 *   "line":"<line>",
2289 *   "column":"<column>",
2290 *
2291 * @param {SourceLocation} location The location to serialize, may be undefined.
2292 */
2293function serializeLocationFields (location, content) {
2294  if (!location) {
2295    return;
2296  }
2297  content.position = location.position;
2298  var line = location.line;
2299  if (!IS_UNDEFINED(line)) {
2300    content.line = line;
2301  }
2302  var column = location.column;
2303  if (!IS_UNDEFINED(column)) {
2304    content.column = column;
2305  }
2306}
2307
2308
2309/**
2310 * Serialize property information to the following JSON format for building the
2311 * array of properties.
2312 *
2313 *   {"name":"<property name>",
2314 *    "attributes":<number>,
2315 *    "propertyType":<number>,
2316 *    "ref":<number>}
2317 *
2318 * If the attribute for the property is PropertyAttribute.None it is not added.
2319 * If the propertyType for the property is PropertyType.Normal it is not added.
2320 * Here are a couple of examples.
2321 *
2322 *   {"name":"hello","ref":1}
2323 *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
2324 *
2325 * @param {PropertyMirror} propertyMirror The property to serialize.
2326 * @returns {Object} Protocol object representing the property.
2327 */
2328JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
2329  var result = {};
2330
2331  result.name = propertyMirror.name();
2332  var propertyValue = propertyMirror.value();
2333  if (this.inlineRefs_() && propertyValue.isValue()) {
2334    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
2335  } else {
2336    if (propertyMirror.attributes() != PropertyAttribute.None) {
2337      result.attributes = propertyMirror.attributes();
2338    }
2339    if (propertyMirror.propertyType() != PropertyType.Normal) {
2340      result.propertyType = propertyMirror.propertyType();
2341    }
2342    result.ref = propertyValue.handle();
2343  }
2344  return result;
2345}
2346
2347
2348JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
2349  content.index = mirror.index();
2350  content.receiver = this.serializeReference(mirror.receiver());
2351  var func = mirror.func();
2352  content.func = this.serializeReference(func);
2353  if (func.script()) {
2354    content.script = this.serializeReference(func.script());
2355  }
2356  content.constructCall = mirror.isConstructCall();
2357  content.atReturn = mirror.isAtReturn();
2358  if (mirror.isAtReturn()) {
2359    content.returnValue = this.serializeReference(mirror.returnValue());
2360  }
2361  content.debuggerFrame = mirror.isDebuggerFrame();
2362  var x = new Array(mirror.argumentCount());
2363  for (var i = 0; i < mirror.argumentCount(); i++) {
2364    var arg = {};
2365    var argument_name = mirror.argumentName(i)
2366    if (argument_name) {
2367      arg.name = argument_name;
2368    }
2369    arg.value = this.serializeReference(mirror.argumentValue(i));
2370    x[i] = arg;
2371  }
2372  content.arguments = x;
2373  var x = new Array(mirror.localCount());
2374  for (var i = 0; i < mirror.localCount(); i++) {
2375    var local = {};
2376    local.name = mirror.localName(i);
2377    local.value = this.serializeReference(mirror.localValue(i));
2378    x[i] = local;
2379  }
2380  content.locals = x;
2381  serializeLocationFields(mirror.sourceLocation(), content);
2382  var source_line_text = mirror.sourceLineText();
2383  if (!IS_UNDEFINED(source_line_text)) {
2384    content.sourceLineText = source_line_text;
2385  }
2386
2387  content.scopes = [];
2388  for (var i = 0; i < mirror.scopeCount(); i++) {
2389    var scope = mirror.scope(i);
2390    content.scopes.push({
2391      type: scope.scopeType(),
2392      index: i
2393    });
2394  }
2395}
2396
2397
2398JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
2399  content.index = mirror.scopeIndex();
2400  content.frameIndex = mirror.frameIndex();
2401  content.type = mirror.scopeType();
2402  content.object = this.inlineRefs_() ?
2403                   this.serializeValue(mirror.scopeObject()) :
2404                   this.serializeReference(mirror.scopeObject());
2405}
2406
2407
2408/**
2409 * Convert a number to a protocol value. For all finite numbers the number
2410 * itself is returned. For non finite numbers NaN, Infinite and
2411 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
2412 * (not including the quotes) is returned.
2413 *
2414 * @param {number} value The number value to convert to a protocol value.
2415 * @returns {number|string} Protocol value.
2416 */
2417function NumberToJSON_(value) {
2418  if (isNaN(value)) {
2419    return 'NaN';
2420  }
2421  if (!NUMBER_IS_FINITE(value)) {
2422    if (value > 0) {
2423      return 'Infinity';
2424    } else {
2425      return '-Infinity';
2426    }
2427  }
2428  return value;
2429}
2430