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