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