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