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