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