• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2006-2008 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// jsminify this file, js2c: jsmin
29
30// Touch the RegExp and Date functions to make sure that date-delay.js and
31// regexp-delay.js has been loaded. This is required as the mirrors use
32// functions within these files through the builtins object.
33RegExp;
34Date;
35
36
37// Handle id counters.
38var next_handle_ = 0;
39var next_transient_handle_ = -1;
40
41// Mirror cache.
42var mirror_cache_ = [];
43
44
45/**
46 * Clear the mirror handle cache.
47 */
48function ClearMirrorCache() {
49  next_handle_ = 0;
50  mirror_cache_ = [];
51}
52
53
54/**
55 * Returns the mirror for a specified value or object.
56 *
57 * @param {value or Object} value the value or object to retreive the mirror for
58 * @param {boolean} transient indicate whether this object is transient and
59 *    should not be added to the mirror cache. The default is not transient.
60 * @returns {Mirror} the mirror reflects the passed value or object
61 */
62function MakeMirror(value, opt_transient) {
63  var mirror;
64
65  // Look for non transient mirrors in the mirror cache.
66  if (!opt_transient) {
67    for (id in mirror_cache_) {
68      mirror = mirror_cache_[id];
69      if (mirror.value() === value) {
70        return mirror;
71      }
72      // Special check for NaN as NaN == NaN is false.
73      if (mirror.isNumber() && isNaN(mirror.value()) &&
74          typeof value == 'number' && isNaN(value)) {
75        return mirror;
76      }
77    }
78  }
79
80  if (IS_UNDEFINED(value)) {
81    mirror = new UndefinedMirror();
82  } else if (IS_NULL(value)) {
83    mirror = new NullMirror();
84  } else if (IS_BOOLEAN(value)) {
85    mirror = new BooleanMirror(value);
86  } else if (IS_NUMBER(value)) {
87    mirror = new NumberMirror(value);
88  } else if (IS_STRING(value)) {
89    mirror = new StringMirror(value);
90  } else if (IS_ARRAY(value)) {
91    mirror = new ArrayMirror(value);
92  } else if (IS_DATE(value)) {
93    mirror = new DateMirror(value);
94  } else if (IS_FUNCTION(value)) {
95    mirror = new FunctionMirror(value);
96  } else if (IS_REGEXP(value)) {
97    mirror = new RegExpMirror(value);
98  } else if (IS_ERROR(value)) {
99    mirror = new ErrorMirror(value);
100  } else if (IS_SCRIPT(value)) {
101    mirror = new ScriptMirror(value);
102  } else {
103    mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient);
104  }
105
106  mirror_cache_[mirror.handle()] = mirror;
107  return mirror;
108}
109
110
111/**
112 * Returns the mirror for a specified mirror handle.
113 *
114 * @param {number} handle the handle to find the mirror for
115 * @returns {Mirror or undefiend} the mirror with the requested handle or
116 *     undefined if no mirror with the requested handle was found
117 */
118function LookupMirror(handle) {
119  return mirror_cache_[handle];
120}
121
122
123/**
124 * Returns the mirror for the undefined value.
125 *
126 * @returns {Mirror} the mirror reflects the undefined value
127 */
128function GetUndefinedMirror() {
129  return MakeMirror(void 0);
130}
131
132
133/**
134 * Inherit the prototype methods from one constructor into another.
135 *
136 * The Function.prototype.inherits from lang.js rewritten as a standalone
137 * function (not on Function.prototype). NOTE: If this file is to be loaded
138 * during bootstrapping this function needs to be revritten using some native
139 * functions as prototype setup using normal JavaScript does not work as
140 * expected during bootstrapping (see mirror.js in r114903).
141 *
142 * @param {function} ctor Constructor function which needs to inherit the
143 *     prototype
144 * @param {function} superCtor Constructor function to inherit prototype from
145 */
146function inherits(ctor, superCtor) {
147  var tempCtor = function(){};
148  tempCtor.prototype = superCtor.prototype;
149  ctor.super_ = superCtor.prototype;
150  ctor.prototype = new tempCtor();
151  ctor.prototype.constructor = ctor;
152}
153
154
155// Type names of the different mirrors.
156const UNDEFINED_TYPE = 'undefined';
157const NULL_TYPE = 'null';
158const BOOLEAN_TYPE = 'boolean';
159const NUMBER_TYPE = 'number';
160const STRING_TYPE = 'string';
161const OBJECT_TYPE = 'object';
162const FUNCTION_TYPE = 'function';
163const REGEXP_TYPE = 'regexp';
164const ERROR_TYPE = 'error';
165const PROPERTY_TYPE = 'property';
166const FRAME_TYPE = 'frame';
167const SCRIPT_TYPE = 'script';
168const CONTEXT_TYPE = 'context';
169const SCOPE_TYPE = 'scope';
170
171// Maximum length when sending strings through the JSON protocol.
172const kMaxProtocolStringLength = 80;
173
174// Different kind of properties.
175PropertyKind = {};
176PropertyKind.Named   = 1;
177PropertyKind.Indexed = 2;
178
179
180// A copy of the PropertyType enum from global.h
181PropertyType = {};
182PropertyType.Normal             = 0;
183PropertyType.Field              = 1;
184PropertyType.ConstantFunction   = 2;
185PropertyType.Callbacks          = 3;
186PropertyType.Interceptor        = 4;
187PropertyType.MapTransition      = 5;
188PropertyType.ConstantTransition = 6;
189PropertyType.NullDescriptor     = 7;
190
191
192// Different attributes for a property.
193PropertyAttribute = {};
194PropertyAttribute.None       = NONE;
195PropertyAttribute.ReadOnly   = READ_ONLY;
196PropertyAttribute.DontEnum   = DONT_ENUM;
197PropertyAttribute.DontDelete = DONT_DELETE;
198
199
200// A copy of the scope types from runtime.cc.
201ScopeType = { Global: 0,
202              Local: 1,
203              With: 2,
204              Closure: 3 };
205
206
207// Mirror hierarchy:
208//   - Mirror
209//     - ValueMirror
210//       - UndefinedMirror
211//       - NullMirror
212//       - NumberMirror
213//       - StringMirror
214//       - ObjectMirror
215//         - FunctionMirror
216//           - UnresolvedFunctionMirror
217//         - ArrayMirror
218//         - DateMirror
219//         - RegExpMirror
220//         - ErrorMirror
221//     - PropertyMirror
222//     - FrameMirror
223//     - ScriptMirror
224
225
226/**
227 * Base class for all mirror objects.
228 * @param {string} type The type of the mirror
229 * @constructor
230 */
231function Mirror(type) {
232  this.type_ = type;
233};
234
235
236Mirror.prototype.type = function() {
237  return this.type_;
238};
239
240
241/**
242 * Check whether the mirror reflects a value.
243 * @returns {boolean} True if the mirror reflects a value.
244 */
245Mirror.prototype.isValue = function() {
246  return this instanceof ValueMirror;
247}
248
249
250/**
251 * Check whether the mirror reflects the undefined value.
252 * @returns {boolean} True if the mirror reflects the undefined value.
253 */
254Mirror.prototype.isUndefined = function() {
255  return this instanceof UndefinedMirror;
256}
257
258
259/**
260 * Check whether the mirror reflects the null value.
261 * @returns {boolean} True if the mirror reflects the null value
262 */
263Mirror.prototype.isNull = function() {
264  return this instanceof NullMirror;
265}
266
267
268/**
269 * Check whether the mirror reflects a boolean value.
270 * @returns {boolean} True if the mirror reflects a boolean value
271 */
272Mirror.prototype.isBoolean = function() {
273  return this instanceof BooleanMirror;
274}
275
276
277/**
278 * Check whether the mirror reflects a number value.
279 * @returns {boolean} True if the mirror reflects a number value
280 */
281Mirror.prototype.isNumber = function() {
282  return this instanceof NumberMirror;
283}
284
285
286/**
287 * Check whether the mirror reflects a string value.
288 * @returns {boolean} True if the mirror reflects a string value
289 */
290Mirror.prototype.isString = function() {
291  return this instanceof StringMirror;
292}
293
294
295/**
296 * Check whether the mirror reflects an object.
297 * @returns {boolean} True if the mirror reflects an object
298 */
299Mirror.prototype.isObject = function() {
300  return this instanceof ObjectMirror;
301}
302
303
304/**
305 * Check whether the mirror reflects a function.
306 * @returns {boolean} True if the mirror reflects a function
307 */
308Mirror.prototype.isFunction = function() {
309  return this instanceof FunctionMirror;
310}
311
312
313/**
314 * Check whether the mirror reflects an unresolved function.
315 * @returns {boolean} True if the mirror reflects an unresolved function
316 */
317Mirror.prototype.isUnresolvedFunction = function() {
318  return this instanceof UnresolvedFunctionMirror;
319}
320
321
322/**
323 * Check whether the mirror reflects an array.
324 * @returns {boolean} True if the mirror reflects an array
325 */
326Mirror.prototype.isArray = function() {
327  return this instanceof ArrayMirror;
328}
329
330
331/**
332 * Check whether the mirror reflects a date.
333 * @returns {boolean} True if the mirror reflects a date
334 */
335Mirror.prototype.isDate = function() {
336  return this instanceof DateMirror;
337}
338
339
340/**
341 * Check whether the mirror reflects a regular expression.
342 * @returns {boolean} True if the mirror reflects a regular expression
343 */
344Mirror.prototype.isRegExp = function() {
345  return this instanceof RegExpMirror;
346}
347
348
349/**
350 * Check whether the mirror reflects an error.
351 * @returns {boolean} True if the mirror reflects an error
352 */
353Mirror.prototype.isError = function() {
354  return this instanceof ErrorMirror;
355}
356
357
358/**
359 * Check whether the mirror reflects a property.
360 * @returns {boolean} True if the mirror reflects a property
361 */
362Mirror.prototype.isProperty = function() {
363  return this instanceof PropertyMirror;
364}
365
366
367/**
368 * Check whether the mirror reflects a stack frame.
369 * @returns {boolean} True if the mirror reflects a stack frame
370 */
371Mirror.prototype.isFrame = function() {
372  return this instanceof FrameMirror;
373}
374
375
376/**
377 * Check whether the mirror reflects a script.
378 * @returns {boolean} True if the mirror reflects a script
379 */
380Mirror.prototype.isScript = function() {
381  return this instanceof ScriptMirror;
382}
383
384
385/**
386 * Check whether the mirror reflects a context.
387 * @returns {boolean} True if the mirror reflects a context
388 */
389Mirror.prototype.isContext = function() {
390  return this instanceof ContextMirror;
391}
392
393
394/**
395 * Check whether the mirror reflects a scope.
396 * @returns {boolean} True if the mirror reflects a scope
397 */
398Mirror.prototype.isScope = function() {
399  return this instanceof ScopeMirror;
400}
401
402
403/**
404 * Allocate a handle id for this object.
405 */
406Mirror.prototype.allocateHandle_ = function() {
407  this.handle_ = next_handle_++;
408}
409
410
411/**
412 * Allocate a transient handle id for this object. Transient handles are
413 * negative.
414 */
415Mirror.prototype.allocateTransientHandle_ = function() {
416  this.handle_ = next_transient_handle_--;
417}
418
419
420Mirror.prototype.toText = function() {
421  // Simpel to text which is used when on specialization in subclass.
422  return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
423}
424
425
426/**
427 * Base class for all value mirror objects.
428 * @param {string} type The type of the mirror
429 * @param {value} value The value reflected by this mirror
430 * @param {boolean} transient indicate whether this object is transient with a
431 *    transient handle
432 * @constructor
433 * @extends Mirror
434 */
435function ValueMirror(type, value, transient) {
436  Mirror.call(this, type);
437  this.value_ = value;
438  if (!transient) {
439    this.allocateHandle_();
440  } else {
441    this.allocateTransientHandle_();
442  }
443}
444inherits(ValueMirror, Mirror);
445
446
447Mirror.prototype.handle = function() {
448  return this.handle_;
449};
450
451
452/**
453 * Check whether this is a primitive value.
454 * @return {boolean} True if the mirror reflects a primitive value
455 */
456ValueMirror.prototype.isPrimitive = function() {
457  var type = this.type();
458  return type === 'undefined' ||
459         type === 'null' ||
460         type === 'boolean' ||
461         type === 'number' ||
462         type === 'string';
463};
464
465
466/**
467 * Get the actual value reflected by this mirror.
468 * @return {value} The value reflected by this mirror
469 */
470ValueMirror.prototype.value = function() {
471  return this.value_;
472};
473
474
475/**
476 * Mirror object for Undefined.
477 * @constructor
478 * @extends ValueMirror
479 */
480function UndefinedMirror() {
481  ValueMirror.call(this, UNDEFINED_TYPE, void 0);
482}
483inherits(UndefinedMirror, ValueMirror);
484
485
486UndefinedMirror.prototype.toText = function() {
487  return 'undefined';
488}
489
490
491/**
492 * Mirror object for null.
493 * @constructor
494 * @extends ValueMirror
495 */
496function NullMirror() {
497  ValueMirror.call(this, NULL_TYPE, null);
498}
499inherits(NullMirror, ValueMirror);
500
501
502NullMirror.prototype.toText = function() {
503  return 'null';
504}
505
506
507/**
508 * Mirror object for boolean values.
509 * @param {boolean} value The boolean value reflected by this mirror
510 * @constructor
511 * @extends ValueMirror
512 */
513function BooleanMirror(value) {
514  ValueMirror.call(this, BOOLEAN_TYPE, value);
515}
516inherits(BooleanMirror, ValueMirror);
517
518
519BooleanMirror.prototype.toText = function() {
520  return this.value_ ? 'true' : 'false';
521}
522
523
524/**
525 * Mirror object for number values.
526 * @param {number} value The number value reflected by this mirror
527 * @constructor
528 * @extends ValueMirror
529 */
530function NumberMirror(value) {
531  ValueMirror.call(this, NUMBER_TYPE, value);
532}
533inherits(NumberMirror, ValueMirror);
534
535
536NumberMirror.prototype.toText = function() {
537  return %NumberToString(this.value_);
538}
539
540
541/**
542 * Mirror object for string values.
543 * @param {string} value The string value reflected by this mirror
544 * @constructor
545 * @extends ValueMirror
546 */
547function StringMirror(value) {
548  ValueMirror.call(this, STRING_TYPE, value);
549}
550inherits(StringMirror, ValueMirror);
551
552
553StringMirror.prototype.length = function() {
554  return this.value_.length;
555};
556
557
558StringMirror.prototype.toText = function() {
559  if (this.length() > kMaxProtocolStringLength) {
560    return this.value_.substring(0, kMaxProtocolStringLength) +
561           '... (length: ' + this.length() + ')';
562  } else {
563    return this.value_;
564  }
565}
566
567
568/**
569 * Mirror object for objects.
570 * @param {object} value The object reflected by this mirror
571 * @param {boolean} transient indicate whether this object is transient with a
572 *    transient handle
573 * @constructor
574 * @extends ValueMirror
575 */
576function ObjectMirror(value, type, transient) {
577  ValueMirror.call(this, type || OBJECT_TYPE, value, transient);
578}
579inherits(ObjectMirror, ValueMirror);
580
581
582ObjectMirror.prototype.className = function() {
583  return %_ClassOf(this.value_);
584};
585
586
587ObjectMirror.prototype.constructorFunction = function() {
588  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
589};
590
591
592ObjectMirror.prototype.prototypeObject = function() {
593  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
594};
595
596
597ObjectMirror.prototype.protoObject = function() {
598  return MakeMirror(%DebugGetPrototype(this.value_));
599};
600
601
602ObjectMirror.prototype.hasNamedInterceptor = function() {
603  // Get information on interceptors for this object.
604  var x = %DebugInterceptorInfo(this.value_);
605  return (x & 2) != 0;
606};
607
608
609ObjectMirror.prototype.hasIndexedInterceptor = function() {
610  // Get information on interceptors for this object.
611  var x = %DebugInterceptorInfo(this.value_);
612  return (x & 1) != 0;
613};
614
615
616/**
617 * Return the property names for this object.
618 * @param {number} kind Indicate whether named, indexed or both kinds of
619 *     properties are requested
620 * @param {number} limit Limit the number of names returend to the specified
621       value
622 * @return {Array} Property names for this object
623 */
624ObjectMirror.prototype.propertyNames = function(kind, limit) {
625  // Find kind and limit and allocate array for the result
626  kind = kind || PropertyKind.Named | PropertyKind.Indexed;
627
628  var propertyNames;
629  var elementNames;
630  var total = 0;
631
632  // Find all the named properties.
633  if (kind & PropertyKind.Named) {
634    // Get the local property names.
635    propertyNames = %DebugLocalPropertyNames(this.value_);
636    total += propertyNames.length;
637
638    // Get names for named interceptor properties if any.
639    if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) {
640      var namedInterceptorNames =
641          %DebugNamedInterceptorPropertyNames(this.value_);
642      if (namedInterceptorNames) {
643        propertyNames = propertyNames.concat(namedInterceptorNames);
644        total += namedInterceptorNames.length;
645      }
646    }
647  }
648
649  // Find all the indexed properties.
650  if (kind & PropertyKind.Indexed) {
651    // Get the local element names.
652    elementNames = %DebugLocalElementNames(this.value_);
653    total += elementNames.length;
654
655    // Get names for indexed interceptor properties.
656    if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) {
657      var indexedInterceptorNames =
658          %DebugIndexedInterceptorElementNames(this.value_);
659      if (indexedInterceptorNames) {
660        elementNames = elementNames.concat(indexedInterceptorNames);
661        total += indexedInterceptorNames.length;
662      }
663    }
664  }
665  limit = Math.min(limit || total, total);
666
667  var names = new Array(limit);
668  var index = 0;
669
670  // Copy names for named properties.
671  if (kind & PropertyKind.Named) {
672    for (var i = 0; index < limit && i < propertyNames.length; i++) {
673      names[index++] = propertyNames[i];
674    }
675  }
676
677  // Copy names for indexed properties.
678  if (kind & PropertyKind.Indexed) {
679    for (var i = 0; index < limit && i < elementNames.length; i++) {
680      names[index++] = elementNames[i];
681    }
682  }
683
684  return names;
685};
686
687
688/**
689 * Return the properties for this object as an array of PropertyMirror objects.
690 * @param {number} kind Indicate whether named, indexed or both kinds of
691 *     properties are requested
692 * @param {number} limit Limit the number of properties returend to the
693       specified value
694 * @return {Array} Property mirrors for this object
695 */
696ObjectMirror.prototype.properties = function(kind, limit) {
697  var names = this.propertyNames(kind, limit);
698  var properties = new Array(names.length);
699  for (var i = 0; i < names.length; i++) {
700    properties[i] = this.property(names[i]);
701  }
702
703  return properties;
704};
705
706
707ObjectMirror.prototype.property = function(name) {
708  var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
709  if (details) {
710    return new PropertyMirror(this, name, details);
711  }
712
713  // Nothing found.
714  return GetUndefinedMirror();
715};
716
717
718
719/**
720 * Try to find a property from its value.
721 * @param {Mirror} value The property value to look for
722 * @return {PropertyMirror} The property with the specified value. If no
723 *     property was found with the specified value UndefinedMirror is returned
724 */
725ObjectMirror.prototype.lookupProperty = function(value) {
726  var properties = this.properties();
727
728  // Look for property value in properties.
729  for (var i = 0; i < properties.length; i++) {
730
731    // Skip properties which are defined through assessors.
732    var property = properties[i];
733    if (property.propertyType() != PropertyType.Callbacks) {
734      if (%_ObjectEquals(property.value_, value.value_)) {
735        return property;
736      }
737    }
738  }
739
740  // Nothing found.
741  return GetUndefinedMirror();
742};
743
744
745/**
746 * Returns objects which has direct references to this object
747 * @param {number} opt_max_objects Optional parameter specifying the maximum
748 *     number of referencing objects to return.
749 * @return {Array} The objects which has direct references to this object.
750 */
751ObjectMirror.prototype.referencedBy = function(opt_max_objects) {
752  // Find all objects with direct references to this object.
753  var result = %DebugReferencedBy(this.value_,
754                                  Mirror.prototype, opt_max_objects || 0);
755
756  // Make mirrors for all the references found.
757  for (var i = 0; i < result.length; i++) {
758    result[i] = MakeMirror(result[i]);
759  }
760
761  return result;
762};
763
764
765ObjectMirror.prototype.toText = function() {
766  var name;
767  var ctor = this.constructorFunction();
768  if (ctor.isUndefined()) {
769    name = this.className();
770  } else {
771    name = ctor.name();
772    if (!name) {
773      name = this.className();
774    }
775  }
776  return '#<' + builtins.GetInstanceName(name) + '>';
777};
778
779
780/**
781 * Mirror object for functions.
782 * @param {function} value The function object reflected by this mirror.
783 * @constructor
784 * @extends ObjectMirror
785 */
786function FunctionMirror(value) {
787  ObjectMirror.call(this, value, FUNCTION_TYPE);
788  this.resolved_ = true;
789}
790inherits(FunctionMirror, ObjectMirror);
791
792
793/**
794 * Returns whether the function is resolved.
795 * @return {boolean} True if the function is resolved. Unresolved functions can
796 *     only originate as functions from stack frames
797 */
798FunctionMirror.prototype.resolved = function() {
799  return this.resolved_;
800};
801
802
803/**
804 * Returns the name of the function.
805 * @return {string} Name of the function
806 */
807FunctionMirror.prototype.name = function() {
808  return %FunctionGetName(this.value_);
809};
810
811
812/**
813 * Returns the inferred name of the function.
814 * @return {string} Name of the function
815 */
816FunctionMirror.prototype.inferredName = function() {
817  return %FunctionGetInferredName(this.value_);
818};
819
820
821/**
822 * Returns the source code for the function.
823 * @return {string or undefined} The source code for the function. If the
824 *     function is not resolved undefined will be returned.
825 */
826FunctionMirror.prototype.source = function() {
827  // Return source if function is resolved. Otherwise just fall through to
828  // return undefined.
829  if (this.resolved()) {
830    return builtins.FunctionSourceString(this.value_);
831  }
832};
833
834
835/**
836 * Returns the script object for the function.
837 * @return {ScriptMirror or undefined} Script object for the function or
838 *     undefined if the function has no script
839 */
840FunctionMirror.prototype.script = function() {
841  // Return script if function is resolved. Otherwise just fall through
842  // to return undefined.
843  if (this.resolved()) {
844    var script = %FunctionGetScript(this.value_);
845    if (script) {
846      return MakeMirror(script);
847    }
848  }
849};
850
851
852/**
853 * Returns objects constructed by this function.
854 * @param {number} opt_max_instances Optional parameter specifying the maximum
855 *     number of instances to return.
856 * @return {Array or undefined} The objects constructed by this function.
857 */
858FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
859  if (this.resolved()) {
860    // Find all objects constructed from this function.
861    var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
862
863    // Make mirrors for all the instances found.
864    for (var i = 0; i < result.length; i++) {
865      result[i] = MakeMirror(result[i]);
866    }
867
868    return result;
869  } else {
870    return [];
871  }
872};
873
874
875FunctionMirror.prototype.toText = function() {
876  return this.source();
877}
878
879
880/**
881 * Mirror object for unresolved functions.
882 * @param {string} value The name for the unresolved function reflected by this
883 *     mirror.
884 * @constructor
885 * @extends ObjectMirror
886 */
887function UnresolvedFunctionMirror(value) {
888  // Construct this using the ValueMirror as an unresolved function is not a
889  // real object but just a string.
890  ValueMirror.call(this, FUNCTION_TYPE, value);
891  this.propertyCount_ = 0;
892  this.elementCount_ = 0;
893  this.resolved_ = false;
894}
895inherits(UnresolvedFunctionMirror, FunctionMirror);
896
897
898UnresolvedFunctionMirror.prototype.className = function() {
899  return 'Function';
900};
901
902
903UnresolvedFunctionMirror.prototype.constructorFunction = function() {
904  return GetUndefinedMirror();
905};
906
907
908UnresolvedFunctionMirror.prototype.prototypeObject = function() {
909  return GetUndefinedMirror();
910};
911
912
913UnresolvedFunctionMirror.prototype.protoObject = function() {
914  return GetUndefinedMirror();
915};
916
917
918UnresolvedFunctionMirror.prototype.name = function() {
919  return this.value_;
920};
921
922
923UnresolvedFunctionMirror.prototype.inferredName = function() {
924  return undefined;
925};
926
927
928UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
929  return [];
930}
931
932
933/**
934 * Mirror object for arrays.
935 * @param {Array} value The Array object reflected by this mirror
936 * @constructor
937 * @extends ObjectMirror
938 */
939function ArrayMirror(value) {
940  ObjectMirror.call(this, value);
941}
942inherits(ArrayMirror, ObjectMirror);
943
944
945ArrayMirror.prototype.length = function() {
946  return this.value_.length;
947};
948
949
950ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) {
951  var from_index = opt_from_index || 0;
952  var to_index = opt_to_index || this.length() - 1;
953  if (from_index > to_index) return new Array();
954  var values = new Array(to_index - from_index + 1);
955  for (var i = from_index; i <= to_index; i++) {
956    var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
957    var value;
958    if (details) {
959      value = new PropertyMirror(this, i, details);
960    } else {
961      value = GetUndefinedMirror();
962    }
963    values[i - from_index] = value;
964  }
965  return values;
966}
967
968
969/**
970 * Mirror object for dates.
971 * @param {Date} value The Date object reflected by this mirror
972 * @constructor
973 * @extends ObjectMirror
974 */
975function DateMirror(value) {
976  ObjectMirror.call(this, value);
977}
978inherits(DateMirror, ObjectMirror);
979
980
981DateMirror.prototype.toText = function() {
982  var s = JSON.stringify(this.value_);
983  return s.substring(1, s.length - 1);  // cut quotes
984}
985
986
987/**
988 * Mirror object for regular expressions.
989 * @param {RegExp} value The RegExp object reflected by this mirror
990 * @constructor
991 * @extends ObjectMirror
992 */
993function RegExpMirror(value) {
994  ObjectMirror.call(this, value, REGEXP_TYPE);
995}
996inherits(RegExpMirror, ObjectMirror);
997
998
999/**
1000 * Returns the source to the regular expression.
1001 * @return {string or undefined} The source to the regular expression
1002 */
1003RegExpMirror.prototype.source = function() {
1004  return this.value_.source;
1005};
1006
1007
1008/**
1009 * Returns whether this regular expression has the global (g) flag set.
1010 * @return {boolean} Value of the global flag
1011 */
1012RegExpMirror.prototype.global = function() {
1013  return this.value_.global;
1014};
1015
1016
1017/**
1018 * Returns whether this regular expression has the ignore case (i) flag set.
1019 * @return {boolean} Value of the ignore case flag
1020 */
1021RegExpMirror.prototype.ignoreCase = function() {
1022  return this.value_.ignoreCase;
1023};
1024
1025
1026/**
1027 * Returns whether this regular expression has the multiline (m) flag set.
1028 * @return {boolean} Value of the multiline flag
1029 */
1030RegExpMirror.prototype.multiline = function() {
1031  return this.value_.multiline;
1032};
1033
1034
1035RegExpMirror.prototype.toText = function() {
1036  // Simpel to text which is used when on specialization in subclass.
1037  return "/" + this.source() + "/";
1038}
1039
1040
1041/**
1042 * Mirror object for error objects.
1043 * @param {Error} value The error object reflected by this mirror
1044 * @constructor
1045 * @extends ObjectMirror
1046 */
1047function ErrorMirror(value) {
1048  ObjectMirror.call(this, value, ERROR_TYPE);
1049}
1050inherits(ErrorMirror, ObjectMirror);
1051
1052
1053/**
1054 * Returns the message for this eror object.
1055 * @return {string or undefined} The message for this eror object
1056 */
1057ErrorMirror.prototype.message = function() {
1058  return this.value_.message;
1059};
1060
1061
1062ErrorMirror.prototype.toText = function() {
1063  // Use the same text representation as in messages.js.
1064  var text;
1065  try {
1066    str = builtins.ToDetailString(this.value_);
1067  } catch (e) {
1068    str = '#<an Error>';
1069  }
1070  return str;
1071}
1072
1073
1074/**
1075 * Base mirror object for properties.
1076 * @param {ObjectMirror} mirror The mirror object having this property
1077 * @param {string} name The name of the property
1078 * @param {Array} details Details about the property
1079 * @constructor
1080 * @extends Mirror
1081 */
1082function PropertyMirror(mirror, name, details) {
1083  Mirror.call(this, PROPERTY_TYPE);
1084  this.mirror_ = mirror;
1085  this.name_ = name;
1086  this.value_ = details[0];
1087  this.details_ = details[1];
1088  if (details.length > 2) {
1089    this.exception_ = details[2]
1090    this.getter_ = details[3];
1091    this.setter_ = details[4];
1092  }
1093}
1094inherits(PropertyMirror, Mirror);
1095
1096
1097PropertyMirror.prototype.isReadOnly = function() {
1098  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
1099}
1100
1101
1102PropertyMirror.prototype.isEnum = function() {
1103  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
1104}
1105
1106
1107PropertyMirror.prototype.canDelete = function() {
1108  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
1109}
1110
1111
1112PropertyMirror.prototype.name = function() {
1113  return this.name_;
1114}
1115
1116
1117PropertyMirror.prototype.isIndexed = function() {
1118  for (var i = 0; i < this.name_.length; i++) {
1119    if (this.name_[i] < '0' || '9' < this.name_[i]) {
1120      return false;
1121    }
1122  }
1123  return true;
1124}
1125
1126
1127PropertyMirror.prototype.value = function() {
1128  return MakeMirror(this.value_, false);
1129}
1130
1131
1132/**
1133 * Returns whether this property value is an exception.
1134 * @return {booolean} True if this property value is an exception
1135 */
1136PropertyMirror.prototype.isException = function() {
1137  return this.exception_ ? true : false;
1138}
1139
1140
1141PropertyMirror.prototype.attributes = function() {
1142  return %DebugPropertyAttributesFromDetails(this.details_);
1143}
1144
1145
1146PropertyMirror.prototype.propertyType = function() {
1147  return %DebugPropertyTypeFromDetails(this.details_);
1148}
1149
1150
1151PropertyMirror.prototype.insertionIndex = function() {
1152  return %DebugPropertyIndexFromDetails(this.details_);
1153}
1154
1155
1156/**
1157 * Returns whether this property has a getter defined through __defineGetter__.
1158 * @return {booolean} True if this property has a getter
1159 */
1160PropertyMirror.prototype.hasGetter = function() {
1161  return this.getter_ ? true : false;
1162}
1163
1164
1165/**
1166 * Returns whether this property has a setter defined through __defineSetter__.
1167 * @return {booolean} True if this property has a setter
1168 */
1169PropertyMirror.prototype.hasSetter = function() {
1170  return this.setter_ ? true : false;
1171}
1172
1173
1174/**
1175 * Returns the getter for this property defined through __defineGetter__.
1176 * @return {Mirror} FunctionMirror reflecting the getter function or
1177 *     UndefinedMirror if there is no getter for this property
1178 */
1179PropertyMirror.prototype.getter = function() {
1180  if (this.hasGetter()) {
1181    return MakeMirror(this.getter_);
1182  } else {
1183    return GetUndefinedMirror();
1184  }
1185}
1186
1187
1188/**
1189 * Returns the setter for this property defined through __defineSetter__.
1190 * @return {Mirror} FunctionMirror reflecting the setter function or
1191 *     UndefinedMirror if there is no setter for this property
1192 */
1193PropertyMirror.prototype.setter = function() {
1194  if (this.hasSetter()) {
1195    return MakeMirror(this.setter_);
1196  } else {
1197    return GetUndefinedMirror();
1198  }
1199}
1200
1201
1202/**
1203 * Returns whether this property is natively implemented by the host or a set
1204 * through JavaScript code.
1205 * @return {boolean} True if the property is
1206 *     UndefinedMirror if there is no setter for this property
1207 */
1208PropertyMirror.prototype.isNative = function() {
1209  return (this.propertyType() == PropertyType.Interceptor) ||
1210         ((this.propertyType() == PropertyType.Callbacks) &&
1211          !this.hasGetter() && !this.hasSetter());
1212}
1213
1214
1215const kFrameDetailsFrameIdIndex = 0;
1216const kFrameDetailsReceiverIndex = 1;
1217const kFrameDetailsFunctionIndex = 2;
1218const kFrameDetailsArgumentCountIndex = 3;
1219const kFrameDetailsLocalCountIndex = 4;
1220const kFrameDetailsSourcePositionIndex = 5;
1221const kFrameDetailsConstructCallIndex = 6;
1222const kFrameDetailsDebuggerFrameIndex = 7;
1223const kFrameDetailsFirstDynamicIndex = 8;
1224
1225const kFrameDetailsNameIndex = 0;
1226const kFrameDetailsValueIndex = 1;
1227const kFrameDetailsNameValueSize = 2;
1228
1229/**
1230 * Wrapper for the frame details information retreived from the VM. The frame
1231 * details from the VM is an array with the following content. See runtime.cc
1232 * Runtime_GetFrameDetails.
1233 *     0: Id
1234 *     1: Receiver
1235 *     2: Function
1236 *     3: Argument count
1237 *     4: Local count
1238 *     5: Source position
1239 *     6: Construct call
1240 *     Arguments name, value
1241 *     Locals name, value
1242 * @param {number} break_id Current break id
1243 * @param {number} index Frame number
1244 * @constructor
1245 */
1246function FrameDetails(break_id, index) {
1247  this.break_id_ = break_id;
1248  this.details_ = %GetFrameDetails(break_id, index);
1249}
1250
1251
1252FrameDetails.prototype.frameId = function() {
1253  %CheckExecutionState(this.break_id_);
1254  return this.details_[kFrameDetailsFrameIdIndex];
1255}
1256
1257
1258FrameDetails.prototype.receiver = function() {
1259  %CheckExecutionState(this.break_id_);
1260  return this.details_[kFrameDetailsReceiverIndex];
1261}
1262
1263
1264FrameDetails.prototype.func = function() {
1265  %CheckExecutionState(this.break_id_);
1266  return this.details_[kFrameDetailsFunctionIndex];
1267}
1268
1269
1270FrameDetails.prototype.isConstructCall = function() {
1271  %CheckExecutionState(this.break_id_);
1272  return this.details_[kFrameDetailsConstructCallIndex];
1273}
1274
1275
1276FrameDetails.prototype.isDebuggerFrame = function() {
1277  %CheckExecutionState(this.break_id_);
1278  return this.details_[kFrameDetailsDebuggerFrameIndex];
1279}
1280
1281
1282FrameDetails.prototype.argumentCount = function() {
1283  %CheckExecutionState(this.break_id_);
1284  return this.details_[kFrameDetailsArgumentCountIndex];
1285}
1286
1287
1288FrameDetails.prototype.argumentName = function(index) {
1289  %CheckExecutionState(this.break_id_);
1290  if (index >= 0 && index < this.argumentCount()) {
1291    return this.details_[kFrameDetailsFirstDynamicIndex +
1292                         index * kFrameDetailsNameValueSize +
1293                         kFrameDetailsNameIndex]
1294  }
1295}
1296
1297
1298FrameDetails.prototype.argumentValue = function(index) {
1299  %CheckExecutionState(this.break_id_);
1300  if (index >= 0 && index < this.argumentCount()) {
1301    return this.details_[kFrameDetailsFirstDynamicIndex +
1302                         index * kFrameDetailsNameValueSize +
1303                         kFrameDetailsValueIndex]
1304  }
1305}
1306
1307
1308FrameDetails.prototype.localCount = function() {
1309  %CheckExecutionState(this.break_id_);
1310  return this.details_[kFrameDetailsLocalCountIndex];
1311}
1312
1313
1314FrameDetails.prototype.sourcePosition = function() {
1315  %CheckExecutionState(this.break_id_);
1316  return this.details_[kFrameDetailsSourcePositionIndex];
1317}
1318
1319
1320FrameDetails.prototype.localName = function(index) {
1321  %CheckExecutionState(this.break_id_);
1322  if (index >= 0 && index < this.localCount()) {
1323    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1324    return this.details_[locals_offset +
1325                         index * kFrameDetailsNameValueSize +
1326                         kFrameDetailsNameIndex]
1327  }
1328}
1329
1330
1331FrameDetails.prototype.localValue = function(index) {
1332  %CheckExecutionState(this.break_id_);
1333  if (index >= 0 && index < this.localCount()) {
1334    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1335    return this.details_[locals_offset +
1336                         index * kFrameDetailsNameValueSize +
1337                         kFrameDetailsValueIndex]
1338  }
1339}
1340
1341
1342FrameDetails.prototype.scopeCount = function() {
1343  return %GetScopeCount(this.break_id_, this.frameId());
1344}
1345
1346
1347/**
1348 * Mirror object for stack frames.
1349 * @param {number} break_id The break id in the VM for which this frame is
1350       valid
1351 * @param {number} index The frame index (top frame is index 0)
1352 * @constructor
1353 * @extends Mirror
1354 */
1355function FrameMirror(break_id, index) {
1356  Mirror.call(this, FRAME_TYPE);
1357  this.break_id_ = break_id;
1358  this.index_ = index;
1359  this.details_ = new FrameDetails(break_id, index);
1360}
1361inherits(FrameMirror, Mirror);
1362
1363
1364FrameMirror.prototype.index = function() {
1365  return this.index_;
1366};
1367
1368
1369FrameMirror.prototype.func = function() {
1370  // Get the function for this frame from the VM.
1371  var f = this.details_.func();
1372
1373  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1374  // value returned from the VM might be a string if the function for the
1375  // frame is unresolved.
1376  if (IS_FUNCTION(f)) {
1377    return MakeMirror(f);
1378  } else {
1379    return new UnresolvedFunctionMirror(f);
1380  }
1381};
1382
1383
1384FrameMirror.prototype.receiver = function() {
1385  return MakeMirror(this.details_.receiver());
1386};
1387
1388
1389FrameMirror.prototype.isConstructCall = function() {
1390  return this.details_.isConstructCall();
1391};
1392
1393
1394FrameMirror.prototype.isDebuggerFrame = function() {
1395  return this.details_.isDebuggerFrame();
1396};
1397
1398
1399FrameMirror.prototype.argumentCount = function() {
1400  return this.details_.argumentCount();
1401};
1402
1403
1404FrameMirror.prototype.argumentName = function(index) {
1405  return this.details_.argumentName(index);
1406};
1407
1408
1409FrameMirror.prototype.argumentValue = function(index) {
1410  return MakeMirror(this.details_.argumentValue(index));
1411};
1412
1413
1414FrameMirror.prototype.localCount = function() {
1415  return this.details_.localCount();
1416};
1417
1418
1419FrameMirror.prototype.localName = function(index) {
1420  return this.details_.localName(index);
1421};
1422
1423
1424FrameMirror.prototype.localValue = function(index) {
1425  return MakeMirror(this.details_.localValue(index));
1426};
1427
1428
1429FrameMirror.prototype.sourcePosition = function() {
1430  return this.details_.sourcePosition();
1431};
1432
1433
1434FrameMirror.prototype.sourceLocation = function() {
1435  if (this.func().resolved() && this.func().script()) {
1436    return this.func().script().locationFromPosition(this.sourcePosition(),
1437                                                     true);
1438  }
1439};
1440
1441
1442FrameMirror.prototype.sourceLine = function() {
1443  if (this.func().resolved()) {
1444    var location = this.sourceLocation();
1445    if (location) {
1446      return location.line;
1447    }
1448  }
1449};
1450
1451
1452FrameMirror.prototype.sourceColumn = function() {
1453  if (this.func().resolved()) {
1454    var location = this.sourceLocation();
1455    if (location) {
1456      return location.column;
1457    }
1458  }
1459};
1460
1461
1462FrameMirror.prototype.sourceLineText = function() {
1463  if (this.func().resolved()) {
1464    var location = this.sourceLocation();
1465    if (location) {
1466      return location.sourceText();
1467    }
1468  }
1469};
1470
1471
1472FrameMirror.prototype.scopeCount = function() {
1473  return this.details_.scopeCount();
1474};
1475
1476
1477FrameMirror.prototype.scope = function(index) {
1478  return new ScopeMirror(this, index);
1479};
1480
1481
1482FrameMirror.prototype.evaluate = function(source, disable_break) {
1483  var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
1484                              source, Boolean(disable_break));
1485  return MakeMirror(result);
1486};
1487
1488
1489FrameMirror.prototype.invocationText = function() {
1490  // Format frame invoaction (receiver, function and arguments).
1491  var result = '';
1492  var func = this.func();
1493  var receiver = this.receiver();
1494  if (this.isConstructCall()) {
1495    // For constructor frames display new followed by the function name.
1496    result += 'new ';
1497    result += func.name() ? func.name() : '[anonymous]';
1498  } else if (this.isDebuggerFrame()) {
1499    result += '[debugger]';
1500  } else {
1501    // If the receiver has a className which is 'global' don't display it.
1502    var display_receiver = !receiver.className || receiver.className() != 'global';
1503    if (display_receiver) {
1504      result += receiver.toText();
1505    }
1506    // Try to find the function as a property in the receiver. Include the
1507    // prototype chain in the lookup.
1508    var property = GetUndefinedMirror();
1509    if (!receiver.isUndefined()) {
1510      for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
1511        property = r.lookupProperty(func);
1512      }
1513    }
1514    if (!property.isUndefined()) {
1515      // The function invoked was found on the receiver. Use the property name
1516      // for the backtrace.
1517      if (!property.isIndexed()) {
1518        if (display_receiver) {
1519          result += '.';
1520        }
1521        result += property.name();
1522      } else {
1523        result += '[';
1524        result += property.name();
1525        result += ']';
1526      }
1527      // Also known as - if the name in the function doesn't match the name
1528      // under which it was looked up.
1529      if (func.name() && func.name() != property.name()) {
1530        result += '(aka ' + func.name() + ')';
1531      }
1532    } else {
1533      // The function invoked was not found on the receiver. Use the function
1534      // name if available for the backtrace.
1535      if (display_receiver) {
1536        result += '.';
1537      }
1538      result += func.name() ? func.name() : '[anonymous]';
1539    }
1540  }
1541
1542  // Render arguments for normal frames.
1543  if (!this.isDebuggerFrame()) {
1544    result += '(';
1545    for (var i = 0; i < this.argumentCount(); i++) {
1546      if (i != 0) result += ', ';
1547      if (this.argumentName(i)) {
1548        result += this.argumentName(i);
1549        result += '=';
1550      }
1551      result += this.argumentValue(i).toText();
1552    }
1553    result += ')';
1554  }
1555
1556  return result;
1557}
1558
1559
1560FrameMirror.prototype.sourceAndPositionText = function() {
1561  // Format source and position.
1562  var result = '';
1563  var func = this.func();
1564  if (func.resolved()) {
1565    if (func.script()) {
1566      if (func.script().name()) {
1567        result += func.script().name();
1568      } else {
1569        result += '[unnamed]';
1570      }
1571      if (!this.isDebuggerFrame()) {
1572        var location = this.sourceLocation();
1573        result += ' line ';
1574        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1575        result += ' column ';
1576        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1577        if (!IS_UNDEFINED(this.sourcePosition())) {
1578          result += ' (position ' + (this.sourcePosition() + 1) + ')';
1579        }
1580      }
1581    } else {
1582      result += '[no source]';
1583    }
1584  } else {
1585    result += '[unresolved]';
1586  }
1587
1588  return result;
1589}
1590
1591
1592FrameMirror.prototype.localsText = function() {
1593  // Format local variables.
1594  var result = '';
1595  var locals_count = this.localCount()
1596  if (locals_count > 0) {
1597    for (var i = 0; i < locals_count; ++i) {
1598      result += '      var ';
1599      result += this.localName(i);
1600      result += ' = ';
1601      result += this.localValue(i).toText();
1602      if (i < locals_count - 1) result += '\n';
1603    }
1604  }
1605
1606  return result;
1607}
1608
1609
1610FrameMirror.prototype.toText = function(opt_locals) {
1611  var result = '';
1612  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1613  result += ' ';
1614  result += this.invocationText();
1615  result += ' ';
1616  result += this.sourceAndPositionText();
1617  if (opt_locals) {
1618    result += '\n';
1619    result += this.localsText();
1620  }
1621  return result;
1622}
1623
1624
1625const kScopeDetailsTypeIndex = 0;
1626const kScopeDetailsObjectIndex = 1;
1627
1628function ScopeDetails(frame, index) {
1629  this.break_id_ = frame.break_id_;
1630  this.details_ = %GetScopeDetails(frame.break_id_,
1631                                   frame.details_.frameId(),
1632                                   index);
1633}
1634
1635
1636ScopeDetails.prototype.type = function() {
1637  %CheckExecutionState(this.break_id_);
1638  return this.details_[kScopeDetailsTypeIndex];
1639}
1640
1641
1642ScopeDetails.prototype.object = function() {
1643  %CheckExecutionState(this.break_id_);
1644  return this.details_[kScopeDetailsObjectIndex];
1645}
1646
1647
1648/**
1649 * Mirror object for scope.
1650 * @param {FrameMirror} frame The frame this scope is a part of
1651 * @param {number} index The scope index in the frame
1652 * @constructor
1653 * @extends Mirror
1654 */
1655function ScopeMirror(frame, index) {
1656  Mirror.call(this, SCOPE_TYPE);
1657  this.frame_index_ = frame.index_;
1658  this.scope_index_ = index;
1659  this.details_ = new ScopeDetails(frame, index);
1660}
1661inherits(ScopeMirror, Mirror);
1662
1663
1664ScopeMirror.prototype.frameIndex = function() {
1665  return this.frame_index_;
1666};
1667
1668
1669ScopeMirror.prototype.scopeIndex = function() {
1670  return this.scope_index_;
1671};
1672
1673
1674ScopeMirror.prototype.scopeType = function() {
1675  return this.details_.type();
1676};
1677
1678
1679ScopeMirror.prototype.scopeObject = function() {
1680  // For local and closure scopes create a transient mirror as these objects are
1681  // created on the fly materializing the local or closure scopes and
1682  // therefore will not preserve identity.
1683  var transient = this.scopeType() == ScopeType.Local ||
1684                  this.scopeType() == ScopeType.Closure;
1685  return MakeMirror(this.details_.object(), transient);
1686};
1687
1688
1689/**
1690 * Mirror object for script source.
1691 * @param {Script} script The script object
1692 * @constructor
1693 * @extends Mirror
1694 */
1695function ScriptMirror(script) {
1696  Mirror.call(this, SCRIPT_TYPE);
1697  this.script_ = script;
1698  this.context_ = new ContextMirror(script.context_data);
1699  this.allocateHandle_();
1700}
1701inherits(ScriptMirror, Mirror);
1702
1703
1704ScriptMirror.prototype.value = function() {
1705  return this.script_;
1706};
1707
1708
1709ScriptMirror.prototype.name = function() {
1710  return this.script_.name;
1711};
1712
1713
1714ScriptMirror.prototype.id = function() {
1715  return this.script_.id;
1716};
1717
1718
1719ScriptMirror.prototype.source = function() {
1720  return this.script_.source;
1721};
1722
1723
1724ScriptMirror.prototype.lineOffset = function() {
1725  return this.script_.line_offset;
1726};
1727
1728
1729ScriptMirror.prototype.columnOffset = function() {
1730  return this.script_.column_offset;
1731};
1732
1733
1734ScriptMirror.prototype.data = function() {
1735  return this.script_.data;
1736};
1737
1738
1739ScriptMirror.prototype.scriptType = function() {
1740  return this.script_.type;
1741};
1742
1743
1744ScriptMirror.prototype.compilationType = function() {
1745  return this.script_.compilation_type;
1746};
1747
1748
1749ScriptMirror.prototype.lineCount = function() {
1750  return this.script_.lineCount();
1751};
1752
1753
1754ScriptMirror.prototype.locationFromPosition = function(
1755    position, include_resource_offset) {
1756  return this.script_.locationFromPosition(position, include_resource_offset);
1757}
1758
1759
1760ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1761  return this.script_.sourceSlice(opt_from_line, opt_to_line);
1762}
1763
1764
1765ScriptMirror.prototype.context = function() {
1766  return this.context_;
1767};
1768
1769
1770ScriptMirror.prototype.evalFromFunction = function() {
1771  return MakeMirror(this.script_.eval_from_function);
1772};
1773
1774
1775ScriptMirror.prototype.evalFromLocation = function() {
1776  var eval_from_function = this.evalFromFunction();
1777  if (!eval_from_function.isUndefined()) {
1778    var position = this.script_.eval_from_position;
1779    return eval_from_function.script().locationFromPosition(position, true);
1780  }
1781};
1782
1783
1784ScriptMirror.prototype.toText = function() {
1785  var result = '';
1786  result += this.name();
1787  result += ' (lines: ';
1788  if (this.lineOffset() > 0) {
1789    result += this.lineOffset();
1790    result += '-';
1791    result += this.lineOffset() + this.lineCount() - 1;
1792  } else {
1793    result += this.lineCount();
1794  }
1795  result += ')';
1796  return result;
1797}
1798
1799
1800/**
1801 * Mirror object for context.
1802 * @param {Object} data The context data
1803 * @constructor
1804 * @extends Mirror
1805 */
1806function ContextMirror(data) {
1807  Mirror.call(this, CONTEXT_TYPE);
1808  this.data_ = data;
1809  this.allocateHandle_();
1810}
1811inherits(ContextMirror, Mirror);
1812
1813
1814ContextMirror.prototype.data = function() {
1815  return this.data_;
1816};
1817
1818
1819/**
1820 * Returns a mirror serializer
1821 *
1822 * @param {boolean} details Set to true to include details
1823 * @param {Object} options Options comtrolling the serialization
1824 *     The following options can be set:
1825 *       includeSource: include ths full source of scripts
1826 * @returns {MirrorSerializer} mirror serializer
1827 */
1828function MakeMirrorSerializer(details, options) {
1829  return new JSONProtocolSerializer(details, options);
1830}
1831
1832
1833/**
1834 * Object for serializing a mirror objects and its direct references.
1835 * @param {boolean} details Indicates whether to include details for the mirror
1836 *     serialized
1837 * @constructor
1838 */
1839function JSONProtocolSerializer(details, options) {
1840  this.details_ = details;
1841  this.options_ = options;
1842  this.mirrors_ = [ ];
1843}
1844
1845
1846/**
1847 * Returns a serialization of an object reference. The referenced object are
1848 * added to the serialization state.
1849 *
1850 * @param {Mirror} mirror The mirror to serialize
1851 * @returns {String} JSON serialization
1852 */
1853JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1854  return this.serialize_(mirror, true, true);
1855}
1856
1857
1858/**
1859 * Returns a serialization of an object value. The referenced objects are
1860 * added to the serialization state.
1861 *
1862 * @param {Mirror} mirror The mirror to serialize
1863 * @returns {String} JSON serialization
1864 */
1865JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1866  var json = this.serialize_(mirror, false, true);
1867  return json;
1868}
1869
1870
1871/**
1872 * Returns a serialization of all the objects referenced.
1873 *
1874 * @param {Mirror} mirror The mirror to serialize.
1875 * @returns {Array.<Object>} Array of the referenced objects converted to
1876 *     protcol objects.
1877 */
1878JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
1879  // Collect the protocol representation of the referenced objects in an array.
1880  var content = [];
1881
1882  // Get the number of referenced objects.
1883  var count = this.mirrors_.length;
1884
1885  for (var i = 0; i < count; i++) {
1886    content.push(this.serialize_(this.mirrors_[i], false, false));
1887  }
1888
1889  return content;
1890}
1891
1892
1893JSONProtocolSerializer.prototype.includeSource_ = function() {
1894  return this.options_ && this.options_.includeSource;
1895}
1896
1897
1898JSONProtocolSerializer.prototype.inlineRefs_ = function() {
1899  return this.options_ && this.options_.inlineRefs;
1900}
1901
1902
1903JSONProtocolSerializer.prototype.add_ = function(mirror) {
1904  // If this mirror is already in the list just return.
1905  for (var i = 0; i < this.mirrors_.length; i++) {
1906    if (this.mirrors_[i] === mirror) {
1907      return;
1908    }
1909  }
1910
1911  // Add the mirror to the list of mirrors to be serialized.
1912  this.mirrors_.push(mirror);
1913}
1914
1915
1916/**
1917 * Formats mirror object to protocol reference object with some data that can
1918 * be used to display the value in debugger.
1919 * @param {Mirror} mirror Mirror to serialize.
1920 * @return {Object} Protocol reference object.
1921 */
1922JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
1923    function(mirror) {
1924  var o = {};
1925  o.ref = mirror.handle();
1926  o.type = mirror.type();
1927  switch (mirror.type()) {
1928    case UNDEFINED_TYPE:
1929    case NULL_TYPE:
1930    case BOOLEAN_TYPE:
1931    case NUMBER_TYPE:
1932      o.value = mirror.value();
1933      break;
1934    case STRING_TYPE:
1935      // Limit string length.
1936      o.value = mirror.toText();
1937      break;
1938    case FUNCTION_TYPE:
1939      o.name = mirror.name();
1940      o.inferredName = mirror.inferredName();
1941      if (mirror.script()) {
1942        o.scriptId = mirror.script().id();
1943      }
1944      break;
1945    case ERROR_TYPE:
1946    case REGEXP_TYPE:
1947      o.value = mirror.toText();
1948      break;
1949    case OBJECT_TYPE:
1950      o.className = mirror.className();
1951      break;
1952  }
1953  return o;
1954};
1955
1956
1957JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
1958                                                       details) {
1959  // If serializing a reference to a mirror just return the reference and add
1960  // the mirror to the referenced mirrors.
1961  if (reference &&
1962      (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
1963    if (this.inlineRefs_() && mirror.isValue()) {
1964      return this.serializeReferenceWithDisplayData_(mirror);
1965    } else {
1966      this.add_(mirror);
1967      return {'ref' : mirror.handle()};
1968    }
1969  }
1970
1971  // Collect the JSON property/value pairs.
1972  var content = {};
1973
1974  // Add the mirror handle.
1975  if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
1976    content.handle = mirror.handle();
1977  }
1978
1979  // Always add the type.
1980  content.type = mirror.type();
1981
1982  switch (mirror.type()) {
1983    case UNDEFINED_TYPE:
1984    case NULL_TYPE:
1985      // Undefined and null are represented just by their type.
1986      break;
1987
1988    case BOOLEAN_TYPE:
1989      // Boolean values are simply represented by their value.
1990      content.value = mirror.value();
1991      break;
1992
1993    case NUMBER_TYPE:
1994      // Number values are simply represented by their value.
1995      content.value = NumberToJSON_(mirror.value());
1996      break;
1997
1998    case STRING_TYPE:
1999      // String values might have their value cropped to keep down size.
2000      if (mirror.length() > kMaxProtocolStringLength) {
2001        var str = mirror.value().substring(0, kMaxProtocolStringLength);
2002        content.value = str;
2003        content.fromIndex = 0;
2004        content.toIndex = kMaxProtocolStringLength;
2005      } else {
2006        content.value = mirror.value();
2007      }
2008      content.length = mirror.length();
2009      break;
2010
2011    case OBJECT_TYPE:
2012    case FUNCTION_TYPE:
2013    case ERROR_TYPE:
2014    case REGEXP_TYPE:
2015      // Add object representation.
2016      this.serializeObject_(mirror, content, details);
2017      break;
2018
2019    case PROPERTY_TYPE:
2020      throw new Error('PropertyMirror cannot be serialized independeltly')
2021      break;
2022
2023    case FRAME_TYPE:
2024      // Add object representation.
2025      this.serializeFrame_(mirror, content);
2026      break;
2027
2028    case SCOPE_TYPE:
2029      // Add object representation.
2030      this.serializeScope_(mirror, content);
2031      break;
2032
2033    case SCRIPT_TYPE:
2034      // Script is represented by id, name and source attributes.
2035      if (mirror.name()) {
2036        content.name = mirror.name();
2037      }
2038      content.id = mirror.id();
2039      content.lineOffset = mirror.lineOffset();
2040      content.columnOffset = mirror.columnOffset();
2041      content.lineCount = mirror.lineCount();
2042      if (mirror.data()) {
2043        content.data = mirror.data();
2044      }
2045      if (this.includeSource_()) {
2046        content.source = mirror.source();
2047      } else {
2048        var sourceStart = mirror.source().substring(0, 80);
2049        content.sourceStart = sourceStart;
2050      }
2051      content.sourceLength = mirror.source().length;
2052      content.scriptType = mirror.scriptType();
2053      content.compilationType = mirror.compilationType();
2054      // For compilation type eval emit information on the script from which
2055      // eval was called if a script is present.
2056      if (mirror.compilationType() == 1 &&
2057          mirror.evalFromFunction().script()) {
2058        content.evalFromScript =
2059            this.serializeReference(mirror.evalFromFunction().script());
2060        var evalFromLocation = mirror.evalFromLocation()
2061        content.evalFromLocation = { line: evalFromLocation.line,
2062                                     column: evalFromLocation.column}
2063      }
2064      if (mirror.context()) {
2065        content.context = this.serializeReference(mirror.context());
2066      }
2067      break;
2068
2069    case CONTEXT_TYPE:
2070      content.data = mirror.data();
2071      break;
2072  }
2073
2074  // Always add the text representation.
2075  content.text = mirror.toText();
2076
2077  // Create and return the JSON string.
2078  return content;
2079}
2080
2081
2082/**
2083 * Serialize object information to the following JSON format.
2084 *
2085 *   {"className":"<class name>",
2086 *    "constructorFunction":{"ref":<number>},
2087 *    "protoObject":{"ref":<number>},
2088 *    "prototypeObject":{"ref":<number>},
2089 *    "namedInterceptor":<boolean>,
2090 *    "indexedInterceptor":<boolean>,
2091 *    "properties":[<properties>]}
2092 */
2093JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
2094                                                             details) {
2095  // Add general object properties.
2096  content.className = mirror.className();
2097  content.constructorFunction =
2098      this.serializeReference(mirror.constructorFunction());
2099  content.protoObject = this.serializeReference(mirror.protoObject());
2100  content.prototypeObject = this.serializeReference(mirror.prototypeObject());
2101
2102  // Add flags to indicate whether there are interceptors.
2103  if (mirror.hasNamedInterceptor()) {
2104    content.namedInterceptor = true;
2105  }
2106  if (mirror.hasIndexedInterceptor()) {
2107    content.indexedInterceptor = true;
2108  }
2109
2110  // Add function specific properties.
2111  if (mirror.isFunction()) {
2112    // Add function specific properties.
2113    content.name = mirror.name();
2114    if (!IS_UNDEFINED(mirror.inferredName())) {
2115      content.inferredName = mirror.inferredName();
2116    }
2117    content.resolved = mirror.resolved();
2118    if (mirror.resolved()) {
2119      content.source = mirror.source();
2120    }
2121    if (mirror.script()) {
2122      content.script = this.serializeReference(mirror.script());
2123    }
2124  }
2125
2126  // Add date specific properties.
2127  if (mirror.isDate()) {
2128    // Add date specific properties.
2129    content.value = mirror.value();
2130  }
2131
2132  // Add actual properties - named properties followed by indexed properties.
2133  var propertyNames = mirror.propertyNames(PropertyKind.Named);
2134  var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
2135  var p = new Array(propertyNames.length + propertyIndexes.length);
2136  for (var i = 0; i < propertyNames.length; i++) {
2137    var propertyMirror = mirror.property(propertyNames[i]);
2138    p[i] = this.serializeProperty_(propertyMirror);
2139    if (details) {
2140      this.add_(propertyMirror.value());
2141    }
2142  }
2143  for (var i = 0; i < propertyIndexes.length; i++) {
2144    var propertyMirror = mirror.property(propertyIndexes[i]);
2145    p[propertyNames.length + i] = this.serializeProperty_(propertyMirror);
2146    if (details) {
2147      this.add_(propertyMirror.value());
2148    }
2149  }
2150  content.properties = p;
2151}
2152
2153
2154/**
2155 * Serialize property information to the following JSON format for building the
2156 * array of properties.
2157 *
2158 *   {"name":"<property name>",
2159 *    "attributes":<number>,
2160 *    "propertyType":<number>,
2161 *    "ref":<number>}
2162 *
2163 * If the attribute for the property is PropertyAttribute.None it is not added.
2164 * If the propertyType for the property is PropertyType.Normal it is not added.
2165 * Here are a couple of examples.
2166 *
2167 *   {"name":"hello","ref":1}
2168 *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
2169 *
2170 * @param {PropertyMirror} propertyMirror The property to serialize.
2171 * @returns {Object} Protocol object representing the property.
2172 */
2173JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
2174  var result = {};
2175
2176  result.name = propertyMirror.name();
2177  var propertyValue = propertyMirror.value();
2178  if (this.inlineRefs_() && propertyValue.isValue()) {
2179    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
2180  } else {
2181    if (propertyMirror.attributes() != PropertyAttribute.None) {
2182      result.attributes = propertyMirror.attributes();
2183    }
2184    if (propertyMirror.propertyType() != PropertyType.Normal) {
2185      result.propertyType = propertyMirror.propertyType();
2186    }
2187    result.ref = propertyValue.handle();
2188  }
2189  return result;
2190}
2191
2192
2193JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
2194  content.index = mirror.index();
2195  content.receiver = this.serializeReference(mirror.receiver());
2196  var func = mirror.func();
2197  content.func = this.serializeReference(func);
2198  if (func.script()) {
2199    content.script = this.serializeReference(func.script());
2200  }
2201  content.constructCall = mirror.isConstructCall();
2202  content.debuggerFrame = mirror.isDebuggerFrame();
2203  var x = new Array(mirror.argumentCount());
2204  for (var i = 0; i < mirror.argumentCount(); i++) {
2205    var arg = {};
2206    var argument_name = mirror.argumentName(i)
2207    if (argument_name) {
2208      arg.name = argument_name;
2209    }
2210    arg.value = this.serializeReference(mirror.argumentValue(i));
2211    x[i] = arg;
2212  }
2213  content.arguments = x;
2214  var x = new Array(mirror.localCount());
2215  for (var i = 0; i < mirror.localCount(); i++) {
2216    var local = {};
2217    local.name = mirror.localName(i);
2218    local.value = this.serializeReference(mirror.localValue(i));
2219    x[i] = local;
2220  }
2221  content.locals = x;
2222  content.position = mirror.sourcePosition();
2223  var line = mirror.sourceLine();
2224  if (!IS_UNDEFINED(line)) {
2225    content.line = line;
2226  }
2227  var column = mirror.sourceColumn();
2228  if (!IS_UNDEFINED(column)) {
2229    content.column = column;
2230  }
2231  var source_line_text = mirror.sourceLineText();
2232  if (!IS_UNDEFINED(source_line_text)) {
2233    content.sourceLineText = source_line_text;
2234  }
2235
2236  content.scopes = [];
2237  for (var i = 0; i < mirror.scopeCount(); i++) {
2238    var scope = mirror.scope(i);
2239    content.scopes.push({
2240      type: scope.scopeType(),
2241      index: i
2242    });
2243  }
2244}
2245
2246
2247JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
2248  content.index = mirror.scopeIndex();
2249  content.frameIndex = mirror.frameIndex();
2250  content.type = mirror.scopeType();
2251  content.object = this.inlineRefs_() ?
2252                   this.serializeValue(mirror.scopeObject()) :
2253                   this.serializeReference(mirror.scopeObject());
2254}
2255
2256
2257/**
2258 * Convert a number to a protocol value. For all finite numbers the number
2259 * itself is returned. For non finite numbers NaN, Infinite and
2260 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
2261 * (not including the quotes) is returned.
2262 *
2263 * @param {number} value The number value to convert to a protocol value.
2264 * @returns {number|string} Protocol value.
2265 */
2266function NumberToJSON_(value) {
2267  if (isNaN(value)) {
2268    return 'NaN';
2269  }
2270  if (!isFinite(value)) {
2271    if (value > 0) {
2272      return 'Infinity';
2273    } else {
2274      return '-Infinity';
2275    }
2276  }
2277  return value;
2278}
2279