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