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