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