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