mirror-debugger.js revision 1e0659c275bb392c045087af4f6b0d7565cb3d77
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 "#<" + 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  %_CallFunction(this, type, Mirror);
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  %_CallFunction(this, UNDEFINED_TYPE, void 0, ValueMirror);
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  %_CallFunction(this, NULL_TYPE, null, ValueMirror);
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  %_CallFunction(this, BOOLEAN_TYPE, value, ValueMirror);
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  %_CallFunction(this, NUMBER_TYPE, value, ValueMirror);
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  %_CallFunction(this, STRING_TYPE, value, ValueMirror);
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  %_CallFunction(this, type || OBJECT_TYPE, value, transient, ValueMirror);
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 '#<' + 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  %_CallFunction(this, value, FUNCTION_TYPE, ObjectMirror);
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  %_CallFunction(this, FUNCTION_TYPE, value, ValueMirror);
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  %_CallFunction(this, value, ObjectMirror);
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  %_CallFunction(this, value, ObjectMirror);
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  %_CallFunction(this, value, REGEXP_TYPE, ObjectMirror);
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  %_CallFunction(this, value, ERROR_TYPE, ObjectMirror);
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 = %_CallFunction(this.value_, builtins.errorToString);
1088  } catch (e) {
1089    str = '#<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  %_CallFunction(this, PROPERTY_TYPE, Mirror);
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 kFrameDetailsAtReturnIndex = 7;
1244const kFrameDetailsDebuggerFrameIndex = 8;
1245const kFrameDetailsFirstDynamicIndex = 9;
1246
1247const kFrameDetailsNameIndex = 0;
1248const kFrameDetailsValueIndex = 1;
1249const kFrameDetailsNameValueSize = 2;
1250
1251/**
1252 * Wrapper for the frame details information retreived from the VM. The frame
1253 * details from the VM is an array with the following content. See runtime.cc
1254 * Runtime_GetFrameDetails.
1255 *     0: Id
1256 *     1: Receiver
1257 *     2: Function
1258 *     3: Argument count
1259 *     4: Local count
1260 *     5: Source position
1261 *     6: Construct call
1262 *     7: Is at return
1263 *     8: Debugger frame
1264 *     Arguments name, value
1265 *     Locals name, value
1266 *     Return value if any
1267 * @param {number} break_id Current break id
1268 * @param {number} index Frame number
1269 * @constructor
1270 */
1271function FrameDetails(break_id, index) {
1272  this.break_id_ = break_id;
1273  this.details_ = %GetFrameDetails(break_id, index);
1274}
1275
1276
1277FrameDetails.prototype.frameId = function() {
1278  %CheckExecutionState(this.break_id_);
1279  return this.details_[kFrameDetailsFrameIdIndex];
1280}
1281
1282
1283FrameDetails.prototype.receiver = function() {
1284  %CheckExecutionState(this.break_id_);
1285  return this.details_[kFrameDetailsReceiverIndex];
1286}
1287
1288
1289FrameDetails.prototype.func = function() {
1290  %CheckExecutionState(this.break_id_);
1291  return this.details_[kFrameDetailsFunctionIndex];
1292}
1293
1294
1295FrameDetails.prototype.isConstructCall = function() {
1296  %CheckExecutionState(this.break_id_);
1297  return this.details_[kFrameDetailsConstructCallIndex];
1298}
1299
1300
1301FrameDetails.prototype.isAtReturn = function() {
1302  %CheckExecutionState(this.break_id_);
1303  return this.details_[kFrameDetailsAtReturnIndex];
1304}
1305
1306
1307FrameDetails.prototype.isDebuggerFrame = function() {
1308  %CheckExecutionState(this.break_id_);
1309  return this.details_[kFrameDetailsDebuggerFrameIndex];
1310}
1311
1312
1313FrameDetails.prototype.argumentCount = function() {
1314  %CheckExecutionState(this.break_id_);
1315  return this.details_[kFrameDetailsArgumentCountIndex];
1316}
1317
1318
1319FrameDetails.prototype.argumentName = function(index) {
1320  %CheckExecutionState(this.break_id_);
1321  if (index >= 0 && index < this.argumentCount()) {
1322    return this.details_[kFrameDetailsFirstDynamicIndex +
1323                         index * kFrameDetailsNameValueSize +
1324                         kFrameDetailsNameIndex]
1325  }
1326}
1327
1328
1329FrameDetails.prototype.argumentValue = function(index) {
1330  %CheckExecutionState(this.break_id_);
1331  if (index >= 0 && index < this.argumentCount()) {
1332    return this.details_[kFrameDetailsFirstDynamicIndex +
1333                         index * kFrameDetailsNameValueSize +
1334                         kFrameDetailsValueIndex]
1335  }
1336}
1337
1338
1339FrameDetails.prototype.localCount = function() {
1340  %CheckExecutionState(this.break_id_);
1341  return this.details_[kFrameDetailsLocalCountIndex];
1342}
1343
1344
1345FrameDetails.prototype.sourcePosition = function() {
1346  %CheckExecutionState(this.break_id_);
1347  return this.details_[kFrameDetailsSourcePositionIndex];
1348}
1349
1350
1351FrameDetails.prototype.localName = function(index) {
1352  %CheckExecutionState(this.break_id_);
1353  if (index >= 0 && index < this.localCount()) {
1354    var locals_offset = kFrameDetailsFirstDynamicIndex +
1355                        this.argumentCount() * kFrameDetailsNameValueSize
1356    return this.details_[locals_offset +
1357                         index * kFrameDetailsNameValueSize +
1358                         kFrameDetailsNameIndex]
1359  }
1360}
1361
1362
1363FrameDetails.prototype.localValue = function(index) {
1364  %CheckExecutionState(this.break_id_);
1365  if (index >= 0 && index < this.localCount()) {
1366    var locals_offset = kFrameDetailsFirstDynamicIndex +
1367                        this.argumentCount() * kFrameDetailsNameValueSize
1368    return this.details_[locals_offset +
1369                         index * kFrameDetailsNameValueSize +
1370                         kFrameDetailsValueIndex]
1371  }
1372}
1373
1374
1375FrameDetails.prototype.returnValue = function() {
1376  %CheckExecutionState(this.break_id_);
1377  var return_value_offset =
1378      kFrameDetailsFirstDynamicIndex +
1379      (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize;
1380  if (this.details_[kFrameDetailsAtReturnIndex]) {
1381    return this.details_[return_value_offset];
1382  }
1383}
1384
1385
1386FrameDetails.prototype.scopeCount = function() {
1387  return %GetScopeCount(this.break_id_, this.frameId());
1388}
1389
1390
1391/**
1392 * Mirror object for stack frames.
1393 * @param {number} break_id The break id in the VM for which this frame is
1394       valid
1395 * @param {number} index The frame index (top frame is index 0)
1396 * @constructor
1397 * @extends Mirror
1398 */
1399function FrameMirror(break_id, index) {
1400  %_CallFunction(this, FRAME_TYPE, Mirror);
1401  this.break_id_ = break_id;
1402  this.index_ = index;
1403  this.details_ = new FrameDetails(break_id, index);
1404}
1405inherits(FrameMirror, Mirror);
1406
1407
1408FrameMirror.prototype.index = function() {
1409  return this.index_;
1410};
1411
1412
1413FrameMirror.prototype.func = function() {
1414  // Get the function for this frame from the VM.
1415  var f = this.details_.func();
1416
1417  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1418  // value returned from the VM might be a string if the function for the
1419  // frame is unresolved.
1420  if (IS_FUNCTION(f)) {
1421    return MakeMirror(f);
1422  } else {
1423    return new UnresolvedFunctionMirror(f);
1424  }
1425};
1426
1427
1428FrameMirror.prototype.receiver = function() {
1429  return MakeMirror(this.details_.receiver());
1430};
1431
1432
1433FrameMirror.prototype.isConstructCall = function() {
1434  return this.details_.isConstructCall();
1435};
1436
1437
1438FrameMirror.prototype.isAtReturn = function() {
1439  return this.details_.isAtReturn();
1440};
1441
1442
1443FrameMirror.prototype.isDebuggerFrame = function() {
1444  return this.details_.isDebuggerFrame();
1445};
1446
1447
1448FrameMirror.prototype.argumentCount = function() {
1449  return this.details_.argumentCount();
1450};
1451
1452
1453FrameMirror.prototype.argumentName = function(index) {
1454  return this.details_.argumentName(index);
1455};
1456
1457
1458FrameMirror.prototype.argumentValue = function(index) {
1459  return MakeMirror(this.details_.argumentValue(index));
1460};
1461
1462
1463FrameMirror.prototype.localCount = function() {
1464  return this.details_.localCount();
1465};
1466
1467
1468FrameMirror.prototype.localName = function(index) {
1469  return this.details_.localName(index);
1470};
1471
1472
1473FrameMirror.prototype.localValue = function(index) {
1474  return MakeMirror(this.details_.localValue(index));
1475};
1476
1477
1478FrameMirror.prototype.returnValue = function() {
1479  return MakeMirror(this.details_.returnValue());
1480};
1481
1482
1483FrameMirror.prototype.sourcePosition = function() {
1484  return this.details_.sourcePosition();
1485};
1486
1487
1488FrameMirror.prototype.sourceLocation = function() {
1489  if (this.func().resolved() && this.func().script()) {
1490    return this.func().script().locationFromPosition(this.sourcePosition(),
1491                                                     true);
1492  }
1493};
1494
1495
1496FrameMirror.prototype.sourceLine = function() {
1497  if (this.func().resolved()) {
1498    var location = this.sourceLocation();
1499    if (location) {
1500      return location.line;
1501    }
1502  }
1503};
1504
1505
1506FrameMirror.prototype.sourceColumn = function() {
1507  if (this.func().resolved()) {
1508    var location = this.sourceLocation();
1509    if (location) {
1510      return location.column;
1511    }
1512  }
1513};
1514
1515
1516FrameMirror.prototype.sourceLineText = function() {
1517  if (this.func().resolved()) {
1518    var location = this.sourceLocation();
1519    if (location) {
1520      return location.sourceText();
1521    }
1522  }
1523};
1524
1525
1526FrameMirror.prototype.scopeCount = function() {
1527  return this.details_.scopeCount();
1528};
1529
1530
1531FrameMirror.prototype.scope = function(index) {
1532  return new ScopeMirror(this, index);
1533};
1534
1535
1536FrameMirror.prototype.evaluate = function(source, disable_break, opt_context_object) {
1537  var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
1538                              source, Boolean(disable_break), opt_context_object);
1539  return MakeMirror(result);
1540};
1541
1542
1543FrameMirror.prototype.invocationText = function() {
1544  // Format frame invoaction (receiver, function and arguments).
1545  var result = '';
1546  var func = this.func();
1547  var receiver = this.receiver();
1548  if (this.isConstructCall()) {
1549    // For constructor frames display new followed by the function name.
1550    result += 'new ';
1551    result += func.name() ? func.name() : '[anonymous]';
1552  } else if (this.isDebuggerFrame()) {
1553    result += '[debugger]';
1554  } else {
1555    // If the receiver has a className which is 'global' don't display it.
1556    var display_receiver = !receiver.className || receiver.className() != 'global';
1557    if (display_receiver) {
1558      result += receiver.toText();
1559    }
1560    // Try to find the function as a property in the receiver. Include the
1561    // prototype chain in the lookup.
1562    var property = GetUndefinedMirror();
1563    if (!receiver.isUndefined()) {
1564      for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
1565        property = r.lookupProperty(func);
1566      }
1567    }
1568    if (!property.isUndefined()) {
1569      // The function invoked was found on the receiver. Use the property name
1570      // for the backtrace.
1571      if (!property.isIndexed()) {
1572        if (display_receiver) {
1573          result += '.';
1574        }
1575        result += property.name();
1576      } else {
1577        result += '[';
1578        result += property.name();
1579        result += ']';
1580      }
1581      // Also known as - if the name in the function doesn't match the name
1582      // under which it was looked up.
1583      if (func.name() && func.name() != property.name()) {
1584        result += '(aka ' + func.name() + ')';
1585      }
1586    } else {
1587      // The function invoked was not found on the receiver. Use the function
1588      // name if available for the backtrace.
1589      if (display_receiver) {
1590        result += '.';
1591      }
1592      result += func.name() ? func.name() : '[anonymous]';
1593    }
1594  }
1595
1596  // Render arguments for normal frames.
1597  if (!this.isDebuggerFrame()) {
1598    result += '(';
1599    for (var i = 0; i < this.argumentCount(); i++) {
1600      if (i != 0) result += ', ';
1601      if (this.argumentName(i)) {
1602        result += this.argumentName(i);
1603        result += '=';
1604      }
1605      result += this.argumentValue(i).toText();
1606    }
1607    result += ')';
1608  }
1609
1610  if (this.isAtReturn()) {
1611    result += ' returning ';
1612    result += this.returnValue().toText();
1613  }
1614
1615  return result;
1616}
1617
1618
1619FrameMirror.prototype.sourceAndPositionText = function() {
1620  // Format source and position.
1621  var result = '';
1622  var func = this.func();
1623  if (func.resolved()) {
1624    if (func.script()) {
1625      if (func.script().name()) {
1626        result += func.script().name();
1627      } else {
1628        result += '[unnamed]';
1629      }
1630      if (!this.isDebuggerFrame()) {
1631        var location = this.sourceLocation();
1632        result += ' line ';
1633        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1634        result += ' column ';
1635        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1636        if (!IS_UNDEFINED(this.sourcePosition())) {
1637          result += ' (position ' + (this.sourcePosition() + 1) + ')';
1638        }
1639      }
1640    } else {
1641      result += '[no source]';
1642    }
1643  } else {
1644    result += '[unresolved]';
1645  }
1646
1647  return result;
1648}
1649
1650
1651FrameMirror.prototype.localsText = function() {
1652  // Format local variables.
1653  var result = '';
1654  var locals_count = this.localCount()
1655  if (locals_count > 0) {
1656    for (var i = 0; i < locals_count; ++i) {
1657      result += '      var ';
1658      result += this.localName(i);
1659      result += ' = ';
1660      result += this.localValue(i).toText();
1661      if (i < locals_count - 1) result += '\n';
1662    }
1663  }
1664
1665  return result;
1666}
1667
1668
1669FrameMirror.prototype.toText = function(opt_locals) {
1670  var result = '';
1671  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1672  result += ' ';
1673  result += this.invocationText();
1674  result += ' ';
1675  result += this.sourceAndPositionText();
1676  if (opt_locals) {
1677    result += '\n';
1678    result += this.localsText();
1679  }
1680  return result;
1681}
1682
1683
1684const kScopeDetailsTypeIndex = 0;
1685const kScopeDetailsObjectIndex = 1;
1686
1687function ScopeDetails(frame, index) {
1688  this.break_id_ = frame.break_id_;
1689  this.details_ = %GetScopeDetails(frame.break_id_,
1690                                   frame.details_.frameId(),
1691                                   index);
1692}
1693
1694
1695ScopeDetails.prototype.type = function() {
1696  %CheckExecutionState(this.break_id_);
1697  return this.details_[kScopeDetailsTypeIndex];
1698}
1699
1700
1701ScopeDetails.prototype.object = function() {
1702  %CheckExecutionState(this.break_id_);
1703  return this.details_[kScopeDetailsObjectIndex];
1704}
1705
1706
1707/**
1708 * Mirror object for scope.
1709 * @param {FrameMirror} frame The frame this scope is a part of
1710 * @param {number} index The scope index in the frame
1711 * @constructor
1712 * @extends Mirror
1713 */
1714function ScopeMirror(frame, index) {
1715  %_CallFunction(this, SCOPE_TYPE, Mirror);
1716  this.frame_index_ = frame.index_;
1717  this.scope_index_ = index;
1718  this.details_ = new ScopeDetails(frame, index);
1719}
1720inherits(ScopeMirror, Mirror);
1721
1722
1723ScopeMirror.prototype.frameIndex = function() {
1724  return this.frame_index_;
1725};
1726
1727
1728ScopeMirror.prototype.scopeIndex = function() {
1729  return this.scope_index_;
1730};
1731
1732
1733ScopeMirror.prototype.scopeType = function() {
1734  return this.details_.type();
1735};
1736
1737
1738ScopeMirror.prototype.scopeObject = function() {
1739  // For local and closure scopes create a transient mirror as these objects are
1740  // created on the fly materializing the local or closure scopes and
1741  // therefore will not preserve identity.
1742  var transient = this.scopeType() == ScopeType.Local ||
1743                  this.scopeType() == ScopeType.Closure;
1744  return MakeMirror(this.details_.object(), transient);
1745};
1746
1747
1748/**
1749 * Mirror object for script source.
1750 * @param {Script} script The script object
1751 * @constructor
1752 * @extends Mirror
1753 */
1754function ScriptMirror(script) {
1755  %_CallFunction(this, SCRIPT_TYPE, Mirror);
1756  this.script_ = script;
1757  this.context_ = new ContextMirror(script.context_data);
1758  this.allocateHandle_();
1759}
1760inherits(ScriptMirror, Mirror);
1761
1762
1763ScriptMirror.prototype.value = function() {
1764  return this.script_;
1765};
1766
1767
1768ScriptMirror.prototype.name = function() {
1769  return this.script_.name || this.script_.nameOrSourceURL();
1770};
1771
1772
1773ScriptMirror.prototype.id = function() {
1774  return this.script_.id;
1775};
1776
1777
1778ScriptMirror.prototype.source = function() {
1779  return this.script_.source;
1780};
1781
1782
1783ScriptMirror.prototype.lineOffset = function() {
1784  return this.script_.line_offset;
1785};
1786
1787
1788ScriptMirror.prototype.columnOffset = function() {
1789  return this.script_.column_offset;
1790};
1791
1792
1793ScriptMirror.prototype.data = function() {
1794  return this.script_.data;
1795};
1796
1797
1798ScriptMirror.prototype.scriptType = function() {
1799  return this.script_.type;
1800};
1801
1802
1803ScriptMirror.prototype.compilationType = function() {
1804  return this.script_.compilation_type;
1805};
1806
1807
1808ScriptMirror.prototype.lineCount = function() {
1809  return this.script_.lineCount();
1810};
1811
1812
1813ScriptMirror.prototype.locationFromPosition = function(
1814    position, include_resource_offset) {
1815  return this.script_.locationFromPosition(position, include_resource_offset);
1816}
1817
1818
1819ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1820  return this.script_.sourceSlice(opt_from_line, opt_to_line);
1821}
1822
1823
1824ScriptMirror.prototype.context = function() {
1825  return this.context_;
1826};
1827
1828
1829ScriptMirror.prototype.evalFromScript = function() {
1830  return MakeMirror(this.script_.eval_from_script);
1831};
1832
1833
1834ScriptMirror.prototype.evalFromFunctionName = function() {
1835  return MakeMirror(this.script_.eval_from_function_name);
1836};
1837
1838
1839ScriptMirror.prototype.evalFromLocation = function() {
1840  var eval_from_script = this.evalFromScript();
1841  if (!eval_from_script.isUndefined()) {
1842    var position = this.script_.eval_from_script_position;
1843    return eval_from_script.locationFromPosition(position, true);
1844  }
1845};
1846
1847
1848ScriptMirror.prototype.toText = function() {
1849  var result = '';
1850  result += this.name();
1851  result += ' (lines: ';
1852  if (this.lineOffset() > 0) {
1853    result += this.lineOffset();
1854    result += '-';
1855    result += this.lineOffset() + this.lineCount() - 1;
1856  } else {
1857    result += this.lineCount();
1858  }
1859  result += ')';
1860  return result;
1861}
1862
1863
1864/**
1865 * Mirror object for context.
1866 * @param {Object} data The context data
1867 * @constructor
1868 * @extends Mirror
1869 */
1870function ContextMirror(data) {
1871  %_CallFunction(this, CONTEXT_TYPE, Mirror);
1872  this.data_ = data;
1873  this.allocateHandle_();
1874}
1875inherits(ContextMirror, Mirror);
1876
1877
1878ContextMirror.prototype.data = function() {
1879  return this.data_;
1880};
1881
1882
1883/**
1884 * Returns a mirror serializer
1885 *
1886 * @param {boolean} details Set to true to include details
1887 * @param {Object} options Options comtrolling the serialization
1888 *     The following options can be set:
1889 *       includeSource: include ths full source of scripts
1890 * @returns {MirrorSerializer} mirror serializer
1891 */
1892function MakeMirrorSerializer(details, options) {
1893  return new JSONProtocolSerializer(details, options);
1894}
1895
1896
1897/**
1898 * Object for serializing a mirror objects and its direct references.
1899 * @param {boolean} details Indicates whether to include details for the mirror
1900 *     serialized
1901 * @constructor
1902 */
1903function JSONProtocolSerializer(details, options) {
1904  this.details_ = details;
1905  this.options_ = options;
1906  this.mirrors_ = [ ];
1907}
1908
1909
1910/**
1911 * Returns a serialization of an object reference. The referenced object are
1912 * added to the serialization state.
1913 *
1914 * @param {Mirror} mirror The mirror to serialize
1915 * @returns {String} JSON serialization
1916 */
1917JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1918  return this.serialize_(mirror, true, true);
1919}
1920
1921
1922/**
1923 * Returns a serialization of an object value. The referenced objects are
1924 * added to the serialization state.
1925 *
1926 * @param {Mirror} mirror The mirror to serialize
1927 * @returns {String} JSON serialization
1928 */
1929JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1930  var json = this.serialize_(mirror, false, true);
1931  return json;
1932}
1933
1934
1935/**
1936 * Returns a serialization of all the objects referenced.
1937 *
1938 * @param {Mirror} mirror The mirror to serialize.
1939 * @returns {Array.<Object>} Array of the referenced objects converted to
1940 *     protcol objects.
1941 */
1942JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
1943  // Collect the protocol representation of the referenced objects in an array.
1944  var content = [];
1945
1946  // Get the number of referenced objects.
1947  var count = this.mirrors_.length;
1948
1949  for (var i = 0; i < count; i++) {
1950    content.push(this.serialize_(this.mirrors_[i], false, false));
1951  }
1952
1953  return content;
1954}
1955
1956
1957JSONProtocolSerializer.prototype.includeSource_ = function() {
1958  return this.options_ && this.options_.includeSource;
1959}
1960
1961
1962JSONProtocolSerializer.prototype.inlineRefs_ = function() {
1963  return this.options_ && this.options_.inlineRefs;
1964}
1965
1966
1967JSONProtocolSerializer.prototype.maxStringLength_ = function() {
1968  if (IS_UNDEFINED(this.options_) ||
1969      IS_UNDEFINED(this.options_.maxStringLength)) {
1970    return kMaxProtocolStringLength;
1971  }
1972  return this.options_.maxStringLength;
1973}
1974
1975
1976JSONProtocolSerializer.prototype.add_ = function(mirror) {
1977  // If this mirror is already in the list just return.
1978  for (var i = 0; i < this.mirrors_.length; i++) {
1979    if (this.mirrors_[i] === mirror) {
1980      return;
1981    }
1982  }
1983
1984  // Add the mirror to the list of mirrors to be serialized.
1985  this.mirrors_.push(mirror);
1986}
1987
1988
1989/**
1990 * Formats mirror object to protocol reference object with some data that can
1991 * be used to display the value in debugger.
1992 * @param {Mirror} mirror Mirror to serialize.
1993 * @return {Object} Protocol reference object.
1994 */
1995JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
1996    function(mirror) {
1997  var o = {};
1998  o.ref = mirror.handle();
1999  o.type = mirror.type();
2000  switch (mirror.type()) {
2001    case UNDEFINED_TYPE:
2002    case NULL_TYPE:
2003    case BOOLEAN_TYPE:
2004    case NUMBER_TYPE:
2005      o.value = mirror.value();
2006      break;
2007    case STRING_TYPE:
2008      o.value = mirror.getTruncatedValue(this.maxStringLength_());
2009      break;
2010    case FUNCTION_TYPE:
2011      o.name = mirror.name();
2012      o.inferredName = mirror.inferredName();
2013      if (mirror.script()) {
2014        o.scriptId = mirror.script().id();
2015      }
2016      break;
2017    case ERROR_TYPE:
2018    case REGEXP_TYPE:
2019      o.value = mirror.toText();
2020      break;
2021    case OBJECT_TYPE:
2022      o.className = mirror.className();
2023      break;
2024  }
2025  return o;
2026};
2027
2028
2029JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
2030                                                       details) {
2031  // If serializing a reference to a mirror just return the reference and add
2032  // the mirror to the referenced mirrors.
2033  if (reference &&
2034      (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
2035    if (this.inlineRefs_() && mirror.isValue()) {
2036      return this.serializeReferenceWithDisplayData_(mirror);
2037    } else {
2038      this.add_(mirror);
2039      return {'ref' : mirror.handle()};
2040    }
2041  }
2042
2043  // Collect the JSON property/value pairs.
2044  var content = {};
2045
2046  // Add the mirror handle.
2047  if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
2048    content.handle = mirror.handle();
2049  }
2050
2051  // Always add the type.
2052  content.type = mirror.type();
2053
2054  switch (mirror.type()) {
2055    case UNDEFINED_TYPE:
2056    case NULL_TYPE:
2057      // Undefined and null are represented just by their type.
2058      break;
2059
2060    case BOOLEAN_TYPE:
2061      // Boolean values are simply represented by their value.
2062      content.value = mirror.value();
2063      break;
2064
2065    case NUMBER_TYPE:
2066      // Number values are simply represented by their value.
2067      content.value = NumberToJSON_(mirror.value());
2068      break;
2069
2070    case STRING_TYPE:
2071      // String values might have their value cropped to keep down size.
2072      if (this.maxStringLength_() != -1 &&
2073          mirror.length() > this.maxStringLength_()) {
2074        var str = mirror.getTruncatedValue(this.maxStringLength_());
2075        content.value = str;
2076        content.fromIndex = 0;
2077        content.toIndex = this.maxStringLength_();
2078      } else {
2079        content.value = mirror.value();
2080      }
2081      content.length = mirror.length();
2082      break;
2083
2084    case OBJECT_TYPE:
2085    case FUNCTION_TYPE:
2086    case ERROR_TYPE:
2087    case REGEXP_TYPE:
2088      // Add object representation.
2089      this.serializeObject_(mirror, content, details);
2090      break;
2091
2092    case PROPERTY_TYPE:
2093      throw new Error('PropertyMirror cannot be serialized independeltly')
2094      break;
2095
2096    case FRAME_TYPE:
2097      // Add object representation.
2098      this.serializeFrame_(mirror, content);
2099      break;
2100
2101    case SCOPE_TYPE:
2102      // Add object representation.
2103      this.serializeScope_(mirror, content);
2104      break;
2105
2106    case SCRIPT_TYPE:
2107      // Script is represented by id, name and source attributes.
2108      if (mirror.name()) {
2109        content.name = mirror.name();
2110      }
2111      content.id = mirror.id();
2112      content.lineOffset = mirror.lineOffset();
2113      content.columnOffset = mirror.columnOffset();
2114      content.lineCount = mirror.lineCount();
2115      if (mirror.data()) {
2116        content.data = mirror.data();
2117      }
2118      if (this.includeSource_()) {
2119        content.source = mirror.source();
2120      } else {
2121        var sourceStart = mirror.source().substring(0, 80);
2122        content.sourceStart = sourceStart;
2123      }
2124      content.sourceLength = mirror.source().length;
2125      content.scriptType = mirror.scriptType();
2126      content.compilationType = mirror.compilationType();
2127      // For compilation type eval emit information on the script from which
2128      // eval was called if a script is present.
2129      if (mirror.compilationType() == 1 &&
2130          mirror.evalFromScript()) {
2131        content.evalFromScript =
2132            this.serializeReference(mirror.evalFromScript());
2133        var evalFromLocation = mirror.evalFromLocation()
2134        if (evalFromLocation) {
2135          content.evalFromLocation = { line: evalFromLocation.line,
2136                                       column: evalFromLocation.column };
2137        }
2138        if (mirror.evalFromFunctionName()) {
2139          content.evalFromFunctionName = mirror.evalFromFunctionName();
2140        }
2141      }
2142      if (mirror.context()) {
2143        content.context = this.serializeReference(mirror.context());
2144      }
2145      break;
2146
2147    case CONTEXT_TYPE:
2148      content.data = mirror.data();
2149      break;
2150  }
2151
2152  // Always add the text representation.
2153  content.text = mirror.toText();
2154
2155  // Create and return the JSON string.
2156  return content;
2157}
2158
2159
2160/**
2161 * Serialize object information to the following JSON format.
2162 *
2163 *   {"className":"<class name>",
2164 *    "constructorFunction":{"ref":<number>},
2165 *    "protoObject":{"ref":<number>},
2166 *    "prototypeObject":{"ref":<number>},
2167 *    "namedInterceptor":<boolean>,
2168 *    "indexedInterceptor":<boolean>,
2169 *    "properties":[<properties>]}
2170 */
2171JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
2172                                                             details) {
2173  // Add general object properties.
2174  content.className = mirror.className();
2175  content.constructorFunction =
2176      this.serializeReference(mirror.constructorFunction());
2177  content.protoObject = this.serializeReference(mirror.protoObject());
2178  content.prototypeObject = this.serializeReference(mirror.prototypeObject());
2179
2180  // Add flags to indicate whether there are interceptors.
2181  if (mirror.hasNamedInterceptor()) {
2182    content.namedInterceptor = true;
2183  }
2184  if (mirror.hasIndexedInterceptor()) {
2185    content.indexedInterceptor = true;
2186  }
2187
2188  // Add function specific properties.
2189  if (mirror.isFunction()) {
2190    // Add function specific properties.
2191    content.name = mirror.name();
2192    if (!IS_UNDEFINED(mirror.inferredName())) {
2193      content.inferredName = mirror.inferredName();
2194    }
2195    content.resolved = mirror.resolved();
2196    if (mirror.resolved()) {
2197      content.source = mirror.source();
2198    }
2199    if (mirror.script()) {
2200      content.script = this.serializeReference(mirror.script());
2201      content.scriptId = mirror.script().id();
2202
2203      serializeLocationFields(mirror.sourceLocation(), content);
2204    }
2205  }
2206
2207  // Add date specific properties.
2208  if (mirror.isDate()) {
2209    // Add date specific properties.
2210    content.value = mirror.value();
2211  }
2212
2213  // Add actual properties - named properties followed by indexed properties.
2214  var propertyNames = mirror.propertyNames(PropertyKind.Named);
2215  var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
2216  var p = new Array(propertyNames.length + propertyIndexes.length);
2217  for (var i = 0; i < propertyNames.length; i++) {
2218    var propertyMirror = mirror.property(propertyNames[i]);
2219    p[i] = this.serializeProperty_(propertyMirror);
2220    if (details) {
2221      this.add_(propertyMirror.value());
2222    }
2223  }
2224  for (var i = 0; i < propertyIndexes.length; i++) {
2225    var propertyMirror = mirror.property(propertyIndexes[i]);
2226    p[propertyNames.length + i] = this.serializeProperty_(propertyMirror);
2227    if (details) {
2228      this.add_(propertyMirror.value());
2229    }
2230  }
2231  content.properties = p;
2232}
2233
2234
2235/**
2236 * Serialize location information to the following JSON format:
2237 *
2238 *   "position":"<position>",
2239 *   "line":"<line>",
2240 *   "column":"<column>",
2241 *
2242 * @param {SourceLocation} location The location to serialize, may be undefined.
2243 */
2244function serializeLocationFields (location, content) {
2245  if (!location) {
2246    return;
2247  }
2248  content.position = location.position;
2249  var line = location.line;
2250  if (!IS_UNDEFINED(line)) {
2251    content.line = line;
2252  }
2253  var column = location.column;
2254  if (!IS_UNDEFINED(column)) {
2255    content.column = column;
2256  }
2257}
2258
2259
2260/**
2261 * Serialize property information to the following JSON format for building the
2262 * array of properties.
2263 *
2264 *   {"name":"<property name>",
2265 *    "attributes":<number>,
2266 *    "propertyType":<number>,
2267 *    "ref":<number>}
2268 *
2269 * If the attribute for the property is PropertyAttribute.None it is not added.
2270 * If the propertyType for the property is PropertyType.Normal it is not added.
2271 * Here are a couple of examples.
2272 *
2273 *   {"name":"hello","ref":1}
2274 *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
2275 *
2276 * @param {PropertyMirror} propertyMirror The property to serialize.
2277 * @returns {Object} Protocol object representing the property.
2278 */
2279JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
2280  var result = {};
2281
2282  result.name = propertyMirror.name();
2283  var propertyValue = propertyMirror.value();
2284  if (this.inlineRefs_() && propertyValue.isValue()) {
2285    result.value = this.serializeReferenceWithDisplayData_(propertyValue);
2286  } else {
2287    if (propertyMirror.attributes() != PropertyAttribute.None) {
2288      result.attributes = propertyMirror.attributes();
2289    }
2290    if (propertyMirror.propertyType() != PropertyType.Normal) {
2291      result.propertyType = propertyMirror.propertyType();
2292    }
2293    result.ref = propertyValue.handle();
2294  }
2295  return result;
2296}
2297
2298
2299JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
2300  content.index = mirror.index();
2301  content.receiver = this.serializeReference(mirror.receiver());
2302  var func = mirror.func();
2303  content.func = this.serializeReference(func);
2304  if (func.script()) {
2305    content.script = this.serializeReference(func.script());
2306  }
2307  content.constructCall = mirror.isConstructCall();
2308  content.atReturn = mirror.isAtReturn();
2309  if (mirror.isAtReturn()) {
2310    content.returnValue = this.serializeReference(mirror.returnValue());
2311  }
2312  content.debuggerFrame = mirror.isDebuggerFrame();
2313  var x = new Array(mirror.argumentCount());
2314  for (var i = 0; i < mirror.argumentCount(); i++) {
2315    var arg = {};
2316    var argument_name = mirror.argumentName(i)
2317    if (argument_name) {
2318      arg.name = argument_name;
2319    }
2320    arg.value = this.serializeReference(mirror.argumentValue(i));
2321    x[i] = arg;
2322  }
2323  content.arguments = x;
2324  var x = new Array(mirror.localCount());
2325  for (var i = 0; i < mirror.localCount(); i++) {
2326    var local = {};
2327    local.name = mirror.localName(i);
2328    local.value = this.serializeReference(mirror.localValue(i));
2329    x[i] = local;
2330  }
2331  content.locals = x;
2332  serializeLocationFields(mirror.sourceLocation(), content);
2333  var source_line_text = mirror.sourceLineText();
2334  if (!IS_UNDEFINED(source_line_text)) {
2335    content.sourceLineText = source_line_text;
2336  }
2337
2338  content.scopes = [];
2339  for (var i = 0; i < mirror.scopeCount(); i++) {
2340    var scope = mirror.scope(i);
2341    content.scopes.push({
2342      type: scope.scopeType(),
2343      index: i
2344    });
2345  }
2346}
2347
2348
2349JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
2350  content.index = mirror.scopeIndex();
2351  content.frameIndex = mirror.frameIndex();
2352  content.type = mirror.scopeType();
2353  content.object = this.inlineRefs_() ?
2354                   this.serializeValue(mirror.scopeObject()) :
2355                   this.serializeReference(mirror.scopeObject());
2356}
2357
2358
2359/**
2360 * Convert a number to a protocol value. For all finite numbers the number
2361 * itself is returned. For non finite numbers NaN, Infinite and
2362 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
2363 * (not including the quotes) is returned.
2364 *
2365 * @param {number} value The number value to convert to a protocol value.
2366 * @returns {number|string} Protocol value.
2367 */
2368function NumberToJSON_(value) {
2369  if (isNaN(value)) {
2370    return 'NaN';
2371  }
2372  if (!NUMBER_IS_FINITE(value)) {
2373    if (value > 0) {
2374      return 'Infinity';
2375    } else {
2376      return '-Infinity';
2377    }
2378  }
2379  return value;
2380}
2381