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