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