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