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