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