blob: caf963e5d86b0acb3de15e15eb1dc0993f16d447 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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// Touch the RegExp and Date functions to make sure that date-delay.js and
29// regexp-delay.js has been loaded. This is required as the mirrors use
30// functions within these files through the builtins object. See the
31// function DateToISO8601_ as an example.
32RegExp;
33Date;
34
35
36function MakeMirror(value) {
37 if (IS_UNDEFINED(value)) return new UndefinedMirror();
38 if (IS_NULL(value)) return new NullMirror();
39 if (IS_BOOLEAN(value)) return new BooleanMirror(value);
40 if (IS_NUMBER(value)) return new NumberMirror(value);
41 if (IS_STRING(value)) return new StringMirror(value);
42 if (IS_ARRAY(value)) return new ArrayMirror(value);
43 if (IS_DATE(value)) return new DateMirror(value);
44 if (IS_FUNCTION(value)) return new FunctionMirror(value);
45 if (IS_REGEXP(value)) return new RegExpMirror(value);
46 if (IS_ERROR(value)) return new ErrorMirror(value);
47 return new ObjectMirror(value);
48}
49
50
51/**
52 * Inherit the prototype methods from one constructor into another.
53 *
54 * The Function.prototype.inherits from lang.js rewritten as a standalone
55 * function (not on Function.prototype). NOTE: If this file is to be loaded
56 * during bootstrapping this function needs to be revritten using some native
57 * functions as prototype setup using normal JavaScript does not work as
58 * expected during bootstrapping (see mirror.js in r114903).
59 *
60 * @param {function} ctor Constructor function which needs to inherit the
61 * prototype
62 * @param {function} superCtor Constructor function to inherit prototype from
63 */
64function inherits(ctor, superCtor) {
65 var tempCtor = function(){};
66 tempCtor.prototype = superCtor.prototype;
67 ctor.super_ = superCtor.prototype;
68 ctor.prototype = new tempCtor();
69 ctor.prototype.constructor = ctor;
70}
71
72
73// Type names of the different mirrors.
74const UNDEFINED_TYPE = 'undefined';
75const NULL_TYPE = 'null';
76const BOOLEAN_TYPE = 'boolean';
77const NUMBER_TYPE = 'number';
78const STRING_TYPE = 'string';
79const OBJECT_TYPE = 'object';
80const FUNCTION_TYPE = 'function';
81const REGEXP_TYPE = 'regexp';
82const ERROR_TYPE = 'error';
83const PROPERTY_TYPE = 'property';
84const ACCESSOR_TYPE = 'accessor';
85const FRAME_TYPE = 'frame';
86const SCRIPT_TYPE = 'script';
87
88// Maximum length when sending strings through the JSON protocol.
89const kMaxProtocolStringLength = 80;
90
91// Different kind of properties.
92PropertyKind = {};
93PropertyKind.Named = 1;
94PropertyKind.Indexed = 2;
95
96
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000097// A copy of the PropertyType enum from global.h
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098PropertyType = {};
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000099PropertyType.Normal = 0;
100PropertyType.Field = 1;
101PropertyType.ConstantFunction = 2;
102PropertyType.Callbacks = 3;
103PropertyType.Interceptor = 4;
104PropertyType.MapTransition = 5;
105PropertyType.ConstantTransition = 6;
106PropertyType.NullDescriptor = 7;
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
109
110// Different attributes for a property.
111PropertyAttribute = {};
112PropertyAttribute.None = NONE;
113PropertyAttribute.ReadOnly = READ_ONLY;
114PropertyAttribute.DontEnum = DONT_ENUM;
115PropertyAttribute.DontDelete = DONT_DELETE;
116
117
118// Mirror hierarchy:
119// - Mirror
120// - ValueMirror
121// - UndefinedMirror
122// - NullMirror
123// - NumberMirror
124// - StringMirror
125// - ObjectMirror
126// - FunctionMirror
127// - UnresolvedFunctionMirror
128// - ArrayMirror
129// - DateMirror
130// - RegExpMirror
131// - ErrorMirror
132// - PropertyMirror
133// - InterceptorPropertyMirror
134// - AccessorMirror
135// - FrameMirror
136// - ScriptMirror
137
138
139/**
140 * Base class for all mirror objects.
141 * @param {string} type The type of the mirror
142 * @constructor
143 */
144function Mirror(type) {
145 this.type_ = type;
146};
147
148
149Mirror.prototype.type = function() {
150 return this.type_;
151};
152
153
154/**
155 * Check whether the mirror reflects the undefined value.
156 * @returns {boolean} True if the mirror reflects the undefined value.
157 */
158Mirror.prototype.isUndefined = function() {
159 return this instanceof UndefinedMirror;
160}
161
162
163/**
164 * Check whether the mirror reflects the null value.
165 * @returns {boolean} True if the mirror reflects the null value
166 */
167Mirror.prototype.isNull = function() {
168 return this instanceof NullMirror;
169}
170
171
172/**
173 * Check whether the mirror reflects a boolean value.
174 * @returns {boolean} True if the mirror reflects a boolean value
175 */
176Mirror.prototype.isBoolean = function() {
177 return this instanceof BooleanMirror;
178}
179
180
181/**
182 * Check whether the mirror reflects a number value.
183 * @returns {boolean} True if the mirror reflects a number value
184 */
185Mirror.prototype.isNumber = function() {
186 return this instanceof NumberMirror;
187}
188
189
190/**
191 * Check whether the mirror reflects a string value.
192 * @returns {boolean} True if the mirror reflects a string value
193 */
194Mirror.prototype.isString = function() {
195 return this instanceof StringMirror;
196}
197
198
199/**
200 * Check whether the mirror reflects an object.
201 * @returns {boolean} True if the mirror reflects an object
202 */
203Mirror.prototype.isObject = function() {
204 return this instanceof ObjectMirror;
205}
206
207
208/**
209 * Check whether the mirror reflects a function.
210 * @returns {boolean} True if the mirror reflects a function
211 */
212Mirror.prototype.isFunction = function() {
213 return this instanceof FunctionMirror;
214}
215
216
217/**
218 * Check whether the mirror reflects an unresolved function.
219 * @returns {boolean} True if the mirror reflects an unresolved function
220 */
221Mirror.prototype.isUnresolvedFunction = function() {
222 return this instanceof UnresolvedFunctionMirror;
223}
224
225
226/**
227 * Check whether the mirror reflects an array.
228 * @returns {boolean} True if the mirror reflects an array
229 */
230Mirror.prototype.isArray = function() {
231 return this instanceof ArrayMirror;
232}
233
234
235/**
236 * Check whether the mirror reflects a date.
237 * @returns {boolean} True if the mirror reflects a date
238 */
239Mirror.prototype.isDate = function() {
240 return this instanceof DateMirror;
241}
242
243
244/**
245 * Check whether the mirror reflects a regular expression.
246 * @returns {boolean} True if the mirror reflects a regular expression
247 */
248Mirror.prototype.isRegExp = function() {
249 return this instanceof RegExpMirror;
250}
251
252
253/**
254 * Check whether the mirror reflects an error.
255 * @returns {boolean} True if the mirror reflects an error
256 */
257Mirror.prototype.isError = function() {
258 return this instanceof ErrorMirror;
259}
260
261
262/**
263 * Check whether the mirror reflects a property.
264 * @returns {boolean} True if the mirror reflects a property
265 */
266Mirror.prototype.isProperty = function() {
267 return this instanceof PropertyMirror;
268}
269
270
271/**
272 * Check whether the mirror reflects a property from an interceptor.
273 * @returns {boolean} True if the mirror reflects a property from an
274 * interceptor
275 */
276Mirror.prototype.isInterceptorProperty = function() {
277 return this instanceof InterceptorPropertyMirror;
278}
279
280
281/**
282 * Check whether the mirror reflects an accessor.
283 * @returns {boolean} True if the mirror reflects an accessor
284 */
285Mirror.prototype.isAccessor = function() {
286 return this instanceof AccessorMirror;
287}
288
289
290/**
291 * Check whether the mirror reflects a stack frame.
292 * @returns {boolean} True if the mirror reflects a stack frame
293 */
294Mirror.prototype.isFrame = function() {
295 return this instanceof FrameMirror;
296}
297
298
299Mirror.prototype.fillJSONType_ = function(content) {
300 content.push(MakeJSONPair_('type', StringToJSON_(this.type())));
301};
302
303
304Mirror.prototype.fillJSON_ = function(content) {
305 this.fillJSONType_(content);
306};
307
308
309/**
310 * Serialize object in JSON format. For the basic mirrors this includes only
311 * the type in the following format.
312 * {"type":"<type name>"}
313 * For specialized mirrors inheriting from the base Mirror
314 * @param {boolean} details Indicate level of details to include
315 * @return {string} JSON serialization
316 */
317Mirror.prototype.toJSONProtocol = function(details, propertiesKind, interceptorPropertiesKind) {
318 var content = new Array();
319 this.fillJSON_(content, details, propertiesKind, interceptorPropertiesKind);
320 content.push(MakeJSONPair_('text', StringToJSON_(this.toText())));
321 return ArrayToJSONObject_(content);
322}
323
324
325Mirror.prototype.toText = function() {
326 // Simpel to text which is used when on specialization in subclass.
327 return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
328}
329
330
331/**
332 * Base class for all value mirror objects.
333 * @param {string} type The type of the mirror
334 * @param {value} value The value reflected by this mirror
335 * @constructor
336 * @extends Mirror
337 */
338function ValueMirror(type, value) {
339 Mirror.call(this, type);
340 this.value_ = value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342inherits(ValueMirror, Mirror);
343
344
345/**
346 * Check whether this is a primitive value.
347 * @return {boolean} True if the mirror reflects a primitive value
348 */
349ValueMirror.prototype.isPrimitive = function() {
350 var type = this.type();
351 return type === 'undefined' ||
352 type === 'null' ||
353 type === 'boolean' ||
354 type === 'number' ||
355 type === 'string';
356};
357
358
359 /**
360 * Get the actual value reflected by this mirror.
361 * @return {value} The value reflected by this mirror
362 */
363ValueMirror.prototype.value = function() {
364 return this.value_;
365};
366
367
368/**
369 * Mirror object for Undefined.
370 * @constructor
371 * @extends ValueMirror
372 */
373function UndefinedMirror() {
374 ValueMirror.call(this, UNDEFINED_TYPE, void 0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000375}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376inherits(UndefinedMirror, ValueMirror);
377
378
379UndefinedMirror.prototype.toText = function() {
380 return 'undefined';
381}
382
383
384/**
385 * Mirror object for null.
386 * @constructor
387 * @extends ValueMirror
388 */
389function NullMirror() {
390 ValueMirror.call(this, NULL_TYPE, null);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000391}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392inherits(NullMirror, ValueMirror);
393
394
395NullMirror.prototype.toText = function() {
396 return 'null';
397}
398
399
400/**
401 * Mirror object for boolean values.
402 * @param {boolean} value The boolean value reflected by this mirror
403 * @constructor
404 * @extends ValueMirror
405 */
406function BooleanMirror(value) {
407 ValueMirror.call(this, BOOLEAN_TYPE, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000408}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409inherits(BooleanMirror, ValueMirror);
410
411
412BooleanMirror.prototype.fillJSON_ = function(content, details) {
413 BooleanMirror.super_.fillJSONType_.call(this, content);
414 content.push(MakeJSONPair_('value', BooleanToJSON_(this.value_)));
415}
416
417
418BooleanMirror.prototype.toText = function() {
419 return this.value_ ? 'true' : 'false';
420}
421
422
423/**
424 * Mirror object for number values.
425 * @param {number} value The number value reflected by this mirror
426 * @constructor
427 * @extends ValueMirror
428 */
429function NumberMirror(value) {
430 ValueMirror.call(this, NUMBER_TYPE, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000431}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432inherits(NumberMirror, ValueMirror);
433
434
435NumberMirror.prototype.fillJSON_ = function(content, details) {
436 NumberMirror.super_.fillJSONType_.call(this, content);
437 content.push(MakeJSONPair_('value', NumberToJSON_(this.value_)));
438}
439
440
441NumberMirror.prototype.toText = function() {
442 return %NumberToString(this.value_);
443}
444
445
446/**
447 * Mirror object for string values.
448 * @param {string} value The string value reflected by this mirror
449 * @constructor
450 * @extends ValueMirror
451 */
452function StringMirror(value) {
453 ValueMirror.call(this, STRING_TYPE, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000454}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455inherits(StringMirror, ValueMirror);
456
457
458StringMirror.prototype.length = function() {
459 return this.value_.length;
460};
461
462
463StringMirror.prototype.fillJSON_ = function(content, details) {
464 StringMirror.super_.fillJSONType_.call(this, content);
465 content.push(MakeJSONPair_('length', NumberToJSON_(this.length())));
466 if (this.length() > kMaxProtocolStringLength) {
467 content.push(MakeJSONPair_('fromIndex', NumberToJSON_(0)));
468 content.push(MakeJSONPair_('toIndex',
469 NumberToJSON_(kMaxProtocolStringLength)));
470 var str = this.value_.substring(0, kMaxProtocolStringLength);
471 content.push(MakeJSONPair_('value', StringToJSON_(str)));
472 } else {
473 content.push(MakeJSONPair_('value', StringToJSON_(this.value_)));
474 }
475}
476
477
478StringMirror.prototype.toText = function() {
479 if (this.length() > kMaxProtocolStringLength) {
480 return this.value_.substring(0, kMaxProtocolStringLength) +
481 '... (length: ' + this.length() + ')';
482 } else {
483 return this.value_;
484 }
485}
486
487
488/**
489 * Mirror object for objects.
490 * @param {object} value The object reflected by this mirror
491 * @constructor
492 * @extends ValueMirror
493 */
494function ObjectMirror(value, type) {
495 ValueMirror.call(this, type || OBJECT_TYPE, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000496}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497inherits(ObjectMirror, ValueMirror);
498
499
500ObjectMirror.prototype.className = function() {
501 return %ClassOf(this.value_);
502};
503
504
505ObjectMirror.prototype.constructorFunction = function() {
506 return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
507};
508
509
510ObjectMirror.prototype.prototypeObject = function() {
511 return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
512};
513
514
515ObjectMirror.prototype.protoObject = function() {
516 return MakeMirror(%GetPrototype(this.value_));
517};
518
519
520ObjectMirror.prototype.hasNamedInterceptor = function() {
521 // Get information on interceptors for this object.
522 var x = %DebugInterceptorInfo(this.value_);
523 return (x & 2) != 0;
524};
525
526
527ObjectMirror.prototype.hasIndexedInterceptor = function() {
528 // Get information on interceptors for this object.
529 var x = %DebugInterceptorInfo(this.value_);
530 return (x & 1) != 0;
531};
532
533
534/**
535 * Return the property names for this object.
536 * @param {number} kind Indicate whether named, indexed or both kinds of
537 * properties are requested
538 * @param {number} limit Limit the number of names returend to the specified
539 value
540 * @return {Array} Property names for this object
541 */
542ObjectMirror.prototype.propertyNames = function(kind, limit) {
543 // Find kind and limit and allocate array for the result
544 kind = kind || PropertyKind.Named | PropertyKind.Indexed;
545
546 var propertyNames;
547 var elementNames;
548 var total = 0;
549 if (kind & PropertyKind.Named) {
550 propertyNames = %DebugLocalPropertyNames(this.value_);
551 total += propertyNames.length;
552 }
553 if (kind & PropertyKind.Indexed) {
554 elementNames = %DebugLocalElementNames(this.value_)
555 total += elementNames.length;
556 }
557 limit = Math.min(limit || total, total);
558
559 var names = new Array(limit);
560 var index = 0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 // Copy names for named properties.
563 if (kind & PropertyKind.Named) {
564 for (var i = 0; index < limit && i < propertyNames.length; i++) {
565 names[index++] = propertyNames[i];
566 }
567 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 // Copy names for indexed properties.
570 if (kind & PropertyKind.Indexed) {
571 for (var i = 0; index < limit && i < elementNames.length; i++) {
572 names[index++] = elementNames[i];
573 }
574 }
575
576 return names;
577};
578
579
580/**
581 * Return the properties for this object as an array of PropertyMirror objects.
582 * @param {number} kind Indicate whether named, indexed or both kinds of
583 * properties are requested
584 * @param {number} limit Limit the number of properties returend to the
585 specified value
586 * @return {Array} Property mirrors for this object
587 */
588ObjectMirror.prototype.properties = function(kind, limit) {
589 var names = this.propertyNames(kind, limit);
590 var properties = new Array(names.length);
591 for (var i = 0; i < names.length; i++) {
592 properties[i] = this.property(names[i]);
593 }
594
595 return properties;
596};
597
598
599/**
600 * Return the interceptor property names for this object.
601 * @param {number} kind Indicate whether named, indexed or both kinds of
602 * interceptor properties are requested
603 * @param {number} limit Limit the number of names returend to the specified
604 value
605 * @return {Array} interceptor property names for this object
606 */
607ObjectMirror.prototype.interceptorPropertyNames = function(kind, limit) {
608 // Find kind.
609 kind = kind || PropertyKind.Named | PropertyKind.Indexed;
610 var namedInterceptorNames;
611 var indexedInterceptorNames;
612
613 // Get names for named interceptor properties.
614 if (this.hasNamedInterceptor() && kind & PropertyKind.Named) {
615 namedInterceptorNames = %DebugNamedInterceptorPropertyNames(this.value_);
616 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 // Get names for indexed interceptor properties.
619 if (this.hasIndexedInterceptor() && kind & PropertyKind.Indexed) {
620 indexedInterceptorNames = %DebugIndexedInterceptorElementNames(this.value_);
621 }
622
623 // Return either retult or both concattenated.
624 if (namedInterceptorNames && indexedInterceptorNames) {
625 return namedInterceptorNames.concat(indexedInterceptorNames);
626 } else if (namedInterceptorNames) {
627 return namedInterceptorNames;
628 } else if (indexedInterceptorNames) {
629 return indexedInterceptorNames;
630 } else {
631 return new Array(0);
632 }
633};
634
635
636/**
637 * Return interceptor properties this object.
638 * @param {number} opt_kind Indicate whether named, indexed or both kinds of
639 * interceptor properties are requested
640 * @param {Array} opt_names Limit the number of properties returned to the
641 specified value
642 * @return {Array} properties this object as an array of PropertyMirror objects
643 */
644ObjectMirror.prototype.interceptorProperties = function(opt_kind, opt_names) {
645 // Find kind.
646 var kind = opt_kind || PropertyKind.Named | PropertyKind.Indexed;
647 var namedInterceptorProperties;
648 var indexedInterceptorProperties;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 // Get values for named interceptor properties.
651 if (kind & PropertyKind.Named) {
652 var names = opt_names || this.interceptorPropertyNames(PropertyKind.Named);
653 namedInterceptorProperties = new Array(names.length);
654 for (i = 0; i < names.length; i++) {
655 var value = %DebugNamedInterceptorPropertyValue(this.value_, names[i]);
656 namedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value);
657 }
658 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 // Get values for indexed interceptor properties.
661 if (kind & PropertyKind.Indexed) {
662 var names = opt_names || this.interceptorPropertyNames(PropertyKind.Indexed);
663 indexedInterceptorProperties = new Array(names.length);
664 for (i = 0; i < names.length; i++) {
665 // Don't try to get the value if the name is not a number.
666 if (IS_NUMBER(names[i])) {
667 var value = %DebugIndexedInterceptorElementValue(this.value_, names[i]);
668 indexedInterceptorProperties[i] = new InterceptorPropertyMirror(this, names[i], value);
669 }
670 }
671 }
672
673 // Return either result or both concattenated.
674 if (namedInterceptorProperties && indexedInterceptorProperties) {
675 return namedInterceptorProperties.concat(indexedInterceptorProperties);
676 } else if (namedInterceptorProperties) {
677 return namedInterceptorProperties;
678 } else {
679 return indexedInterceptorProperties;
680 }
681};
682
683
684ObjectMirror.prototype.property = function(name) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000685 var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686 if (details) {
687 return new PropertyMirror(this, name, details[0], details[1]);
688 }
689
690 // Nothing found.
691 return new UndefinedMirror();
692};
693
694
695
696/**
697 * Try to find a property from its value.
698 * @param {Mirror} value The property value to look for
699 * @return {PropertyMirror} The property with the specified value. If no
700 * property was found with the specified value UndefinedMirror is returned
701 */
702ObjectMirror.prototype.lookupProperty = function(value) {
703 var properties = this.properties();
704
705 // Look for property value in properties.
706 for (var i = 0; i < properties.length; i++) {
707
708 // Skip properties which are defined through assessors.
709 var property = properties[i];
710 if (property.propertyType() != PropertyType.Callbacks) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000711 if (%_ObjectEquals(property.value_, value.value_)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 return property;
713 }
714 }
715 }
716
717 // Nothing found.
718 return new UndefinedMirror();
719};
720
721
722/**
723 * Returns objects which has direct references to this object
724 * @param {number} opt_max_instances Optional parameter specifying the maximum
725 * number of instances to return.
726 * @return {Array} The objects which has direct references to this object.
727 */
728ObjectMirror.prototype.referencedBy = function(opt_max_instances) {
729 // Find all objects constructed from this function.
730 var result = %DebugReferencedBy(this.value_, Mirror.prototype, opt_max_instances || 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732 // Make mirrors for all the instances found.
733 for (var i = 0; i < result.length; i++) {
734 result[i] = MakeMirror(result[i]);
735 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737 return result;
738};
739
740
741ObjectMirror.prototype.fillJSONProperties_ = function(content, kind, name, details) {
742 var propertyNames = this.propertyNames(kind);
743 var x = new Array(propertyNames.length);
744 for (var i = 0; i < propertyNames.length; i++) {
745 x[i] = this.property(propertyNames[i]).toJSONProtocol(details);
746 }
747 content.push(MakeJSONPair_(name || 'properties', ArrayToJSONArray_(x)));
748};
749
750
751ObjectMirror.prototype.fillJSONInterceptorProperties_ = function(content, kind, name, details) {
752 var propertyNames = this.interceptorPropertyNames(kind);
753 var x = new Array(propertyNames.length);
754 for (var i = 0; i < propertyNames.length; i++) {
755 x[i] = properties[i].toJSONProtocol(details);
756 }
757 content.push(MakeJSONPair_(name || 'interceptorProperties', ArrayToJSONArray_(x)));
758};
759
760
761ObjectMirror.prototype.fillJSON_ = function(content, details, propertiesKind, interceptorPropertiesKind) {
762 ObjectMirror.super_.fillJSONType_.call(this, content);
763 content.push(MakeJSONPair_('className', StringToJSON_(this.className())));
764 if (details) {
765 content.push(MakeJSONPair_('constructorFunction', this.constructorFunction().toJSONProtocol(false)));
766 content.push(MakeJSONPair_('protoObject', this.protoObject().toJSONProtocol(false)));
767 content.push(MakeJSONPair_('prototypeObject', this.prototypeObject().toJSONProtocol(false)));
768 }
769 if (details) {
770 this.fillJSONProperties_(content, propertiesKind)
771 if (interceptorPropertiesKind) {
772 this.fillJSONInterceptorProperties_(content, interceptorPropertiesKind)
773 }
774 }
775 if (this.hasNamedInterceptor()) {
776 content.push(MakeJSONPair_('namedInterceptor', BooleanToJSON_(true)));
777 }
778 if (this.hasIndexedInterceptor()) {
779 content.push(MakeJSONPair_('indexedInterceptor', BooleanToJSON_(true)));
780 }
781};
782
783
784ObjectMirror.prototype.toText = function() {
785 var name;
786 var ctor = this.constructorFunction();
787 if (ctor.isUndefined()) {
788 name = this.className();
789 } else {
790 name = ctor.name();
791 if (!name) {
792 name = this.className();
793 }
794 }
795 return '#<' + builtins.GetInstanceName(name) + '>';
796};
797
798
799/**
800 * Mirror object for functions.
801 * @param {function} value The function object reflected by this mirror.
802 * @constructor
803 * @extends ObjectMirror
804 */
805function FunctionMirror(value) {
806 ObjectMirror.call(this, value, FUNCTION_TYPE);
807 this.resolved_ = true;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000808}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000809inherits(FunctionMirror, ObjectMirror);
810
811
812/**
813 * Returns whether the function is resolved.
814 * @return {boolean} True if the function is resolved. Unresolved functions can
815 * only originate as functions from stack frames
816 */
817FunctionMirror.prototype.resolved = function() {
818 return this.resolved_;
819};
820
821
822/**
823 * Returns the name of the function.
824 * @return {string} Name of the function
825 */
826FunctionMirror.prototype.name = function() {
827 return %FunctionGetName(this.value_);
828};
829
830
831/**
832 * Returns the source code for the function.
833 * @return {string or undefined} The source code for the function. If the
834 * function is not resolved undefined will be returned.
835 */
836FunctionMirror.prototype.source = function() {
837 // Return source if function is resolved. Otherwise just fall through to
838 // return undefined.
839 if (this.resolved()) {
840 // This builtins function is context independant (only uses runtime
841 // calls and typeof.
842 return builtins.FunctionSourceString(this.value_);
843 }
844};
845
846
847/**
848 * Returns the script object for the function.
849 * @return {ScriptMirror or undefined} Script object for the function or
850 * undefined if the function has no script
851 */
852FunctionMirror.prototype.script = function() {
853 // Return script if function is resolved. Otherwise just fall through
854 // to return undefined.
855 if (this.resolved()) {
856 var script = %FunctionGetScript(this.value_);
857 if (script) {
858 return new ScriptMirror(script);
859 }
860 }
861};
862
863
864/**
865 * Returns objects constructed by this function.
866 * @param {number} opt_max_instances Optional parameter specifying the maximum
867 * number of instances to return.
868 * @return {Array or undefined} The objects constructed by this function.
869 */
870FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
871 if (this.resolved()) {
872 // Find all objects constructed from this function.
873 var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875 // Make mirrors for all the instances found.
876 for (var i = 0; i < result.length; i++) {
877 result[i] = MakeMirror(result[i]);
878 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000879
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 return result;
881 } else {
882 return [];
883 }
884};
885
886
887FunctionMirror.prototype.fillJSON_ = function(content, details) {
888 // Fill JSON properties from parent (ObjectMirror).
889 FunctionMirror.super_.fillJSON_.call(this, content, details);
890 // Add function specific properties.
891 content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
892 content.push(MakeJSONPair_('resolved', BooleanToJSON_(this.resolved())));
893 if (details && this.resolved()) {
894 content.push(MakeJSONPair_('source', StringToJSON_(this.source())));
895 }
896 if (this.script()) {
897 content.push(MakeJSONPair_('script', this.script().toJSONProtocol()));
898 }
899}
900
901
902FunctionMirror.prototype.toText = function() {
903 return this.source();
904}
905
906
907/**
908 * Mirror object for unresolved functions.
909 * @param {string} value The name for the unresolved function reflected by this
910 * mirror.
911 * @constructor
912 * @extends ObjectMirror
913 */
914function UnresolvedFunctionMirror(value) {
915 // Construct this using the ValueMirror as an unresolved function is not a
916 // real object but just a string.
917 ValueMirror.call(this, FUNCTION_TYPE, value);
918 this.propertyCount_ = 0;
919 this.elementCount_ = 0;
920 this.resolved_ = false;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000921}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922inherits(UnresolvedFunctionMirror, FunctionMirror);
923
924
925UnresolvedFunctionMirror.prototype.className = function() {
926 return 'Function';
927};
928
929
930UnresolvedFunctionMirror.prototype.constructorFunction = function() {
931 return new UndefinedMirror();
932};
933
934
935UnresolvedFunctionMirror.prototype.prototypeObject = function() {
936 return new UndefinedMirror();
937};
938
939
940UnresolvedFunctionMirror.prototype.protoObject = function() {
941 return new UndefinedMirror();
942};
943
944
945UnresolvedFunctionMirror.prototype.name = function() {
946 return this.value_;
947};
948
949
950UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
951 return [];
952}
953
954
955/**
956 * Mirror object for arrays.
957 * @param {Array} value The Array object reflected by this mirror
958 * @constructor
959 * @extends ObjectMirror
960 */
961function ArrayMirror(value) {
962 ObjectMirror.call(this, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000963}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964inherits(ArrayMirror, ObjectMirror);
965
966
967ArrayMirror.prototype.length = function() {
968 return this.value_.length;
969};
970
971
972ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) {
973 var from_index = opt_from_index || 0;
974 var to_index = opt_to_index || this.length() - 1;
975 if (from_index > to_index) return new Array();
976 var values = new Array(to_index - from_index + 1);
977 for (var i = from_index; i <= to_index; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000978 var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 var value;
980 if (details) {
981 value = new PropertyMirror(this, i, details[0], details[1]);
982 } else {
983 value = new UndefinedMirror();
984 }
985 values[i - from_index] = value;
986 }
987 return values;
988}
989
990
991ArrayMirror.prototype.fillJSON_ = function(content, details) {
992 // Fill JSON as for parent (ObjectMirror) but just with named properties.
993 ArrayMirror.super_.fillJSON_.call(this, content, details, PropertyKind.Named);
994 // Fill indexed properties seperately.
995 if (details) {
996 this.fillJSONProperties_(content, PropertyKind.Indexed, 'indexedProperties')
997 }
998 // Add the array length.
999 content.push(MakeJSONPair_('length', NumberToJSON_(this.length())));
1000}
1001
1002
1003/**
1004 * Mirror object for dates.
1005 * @param {Date} value The Date object reflected by this mirror
1006 * @constructor
1007 * @extends ObjectMirror
1008 */
1009function DateMirror(value) {
1010 ObjectMirror.call(this, value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001011}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012inherits(DateMirror, ObjectMirror);
1013
1014
1015DateMirror.prototype.fillJSON_ = function(content, details) {
1016 // Fill JSON properties from parent (ObjectMirror).
1017 DateMirror.super_.fillJSON_.call(this, content, details);
1018 // Add date specific properties.
1019 content.push(MakeJSONPair_('value', DateToJSON_(this.value_)));
1020}
1021
1022
1023DateMirror.prototype.toText = function() {
1024 return DateToISO8601_(this.value_);
1025}
1026
1027
1028/**
1029 * Mirror object for regular expressions.
1030 * @param {RegExp} value The RegExp object reflected by this mirror
1031 * @constructor
1032 * @extends ObjectMirror
1033 */
1034function RegExpMirror(value) {
1035 ObjectMirror.call(this, value, REGEXP_TYPE);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001036}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037inherits(RegExpMirror, ObjectMirror);
1038
1039
1040/**
1041 * Returns the source to the regular expression.
1042 * @return {string or undefined} The source to the regular expression
1043 */
1044RegExpMirror.prototype.source = function() {
1045 return this.value_.source;
1046};
1047
1048
1049/**
1050 * Returns whether this regular expression has the global (g) flag set.
1051 * @return {boolean} Value of the global flag
1052 */
1053RegExpMirror.prototype.global = function() {
1054 return this.value_.global;
1055};
1056
1057
1058/**
1059 * Returns whether this regular expression has the ignore case (i) flag set.
1060 * @return {boolean} Value of the ignore case flag
1061 */
1062RegExpMirror.prototype.ignoreCase = function() {
1063 return this.value_.ignoreCase;
1064};
1065
1066
1067/**
1068 * Returns whether this regular expression has the multiline (m) flag set.
1069 * @return {boolean} Value of the multiline flag
1070 */
1071RegExpMirror.prototype.multiline = function() {
1072 return this.value_.multiline;
1073};
1074
1075
1076RegExpMirror.prototype.fillJSON_ = function(content, details) {
1077 // Fill JSON properties from parent (ObjectMirror).
1078 RegExpMirror.super_.fillJSON_.call(this, content, details);
1079 // Add regexp specific properties.
1080 content.push(MakeJSONPair_('source', StringToJSON_(this.source())));
1081 content.push(MakeJSONPair_('global', BooleanToJSON_(this.global())));
1082 content.push(MakeJSONPair_('ignoreCase', BooleanToJSON_(this.ignoreCase())));
1083 content.push(MakeJSONPair_('multiline', BooleanToJSON_(this.multiline())));
1084}
1085
1086
1087RegExpMirror.prototype.toText = function() {
1088 // Simpel to text which is used when on specialization in subclass.
1089 return "/" + this.source() + "/";
1090}
1091
1092
1093/**
1094 * Mirror object for error objects.
1095 * @param {Error} value The error object reflected by this mirror
1096 * @constructor
1097 * @extends ObjectMirror
1098 */
1099function ErrorMirror(value) {
1100 ObjectMirror.call(this, value, ERROR_TYPE);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001101}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102inherits(ErrorMirror, ObjectMirror);
1103
1104
1105/**
1106 * Returns the message for this eror object.
1107 * @return {string or undefined} The message for this eror object
1108 */
1109ErrorMirror.prototype.message = function() {
1110 return this.value_.message;
1111};
1112
1113
1114ErrorMirror.prototype.fillJSON_ = function(content, details) {
1115 // Fill JSON properties from parent (ObjectMirror).
1116 ErrorMirror.super_.fillJSON_.call(this, content, details);
1117 // Add error specific properties.
1118 content.push(MakeJSONPair_('message', StringToJSON_(this.message())));
1119}
1120
1121
1122ErrorMirror.prototype.toText = function() {
1123 // Use the same text representation as in messages.js.
1124 var text;
1125 try {
1126 str = builtins.ToDetailString(this.value_);
1127 } catch (e) {
1128 str = '#<an Error>';
1129 }
1130 return str;
1131}
1132
1133
1134/**
1135 * Base mirror object for properties.
1136 * @param {ObjectMirror} mirror The mirror object having this property
1137 * @param {string} name The name of the property
1138 * @param {Object} value The value of the property
1139 * @constructor
1140 * @extends Mirror
1141 */
1142function PropertyMirror(mirror, name, value, details) {
1143 Mirror.call(this, PROPERTY_TYPE);
1144 this.mirror_ = mirror;
1145 this.name_ = name;
1146 this.value_ = value;
1147 this.details_ = details;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001148}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149inherits(PropertyMirror, Mirror);
1150
1151
1152PropertyMirror.prototype.isReadOnly = function() {
1153 return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
1154}
1155
1156
1157PropertyMirror.prototype.isEnum = function() {
1158 return (this.attributes() & PropertyAttribute.DontEnum) == 0;
1159}
1160
1161
1162PropertyMirror.prototype.canDelete = function() {
1163 return (this.attributes() & PropertyAttribute.DontDelete) == 0;
1164}
1165
1166
1167PropertyMirror.prototype.name = function() {
1168 return this.name_;
1169}
1170
1171
1172PropertyMirror.prototype.isIndexed = function() {
1173 for (var i = 0; i < this.name_.length; i++) {
1174 if (this.name_[i] < '0' || '9' < this.name_[i]) {
1175 return false;
1176 }
1177 }
1178 return true;
1179}
1180
1181
1182PropertyMirror.prototype.value = function() {
1183 if (this.propertyType() == PropertyType.Callbacks) {
1184 // TODO(1242933): AccessorMirror should have getter/setter values.
1185 return new AccessorMirror();
1186 } else if (this.type() == PropertyType.Interceptor) {
1187 return new UndefinedMirror();
1188 } else {
1189 return MakeMirror(this.value_);
1190 }
1191}
1192
1193
1194PropertyMirror.prototype.attributes = function() {
1195 return %DebugPropertyAttributesFromDetails(this.details_);
1196}
1197
1198
1199PropertyMirror.prototype.propertyType = function() {
1200 return %DebugPropertyTypeFromDetails(this.details_);
1201}
1202
1203
1204PropertyMirror.prototype.insertionIndex = function() {
1205 return %DebugPropertyIndexFromDetails(this.details_);
1206}
1207
1208
1209PropertyMirror.prototype.fillJSON_ = function(content, details) {
1210 content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
1211 content.push(MakeJSONPair_('value', this.value().toJSONProtocol(details)));
1212 if (this.attributes() != PropertyAttribute.None) {
1213 content.push(MakeJSONPair_('attributes', NumberToJSON_(this.attributes())));
1214 }
1215 if (this.propertyType() != PropertyType.Normal) {
1216 content.push(MakeJSONPair_('propertyType', NumberToJSON_(this.propertyType())));
1217 }
1218}
1219
1220
1221/**
1222 * Mirror object for interceptor named properties.
1223 * @param {ObjectMirror} mirror The mirror object having this property
1224 * @param {String} name The name of the property
1225 * @param {value} value The value of the property
1226 * @constructor
1227 * @extends PropertyMirror
1228 */
1229function InterceptorPropertyMirror(mirror, name, value) {
1230 PropertyMirror.call(this, mirror, name, value, PropertyType.Interceptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001231}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232inherits(InterceptorPropertyMirror, PropertyMirror);
1233
1234
1235/**
1236 * Mirror object for property accessors.
1237 * @param {Function} getter The getter function for this accessor
1238 * @param {Function} setter The setter function for this accessor
1239 * @constructor
1240 * @extends Mirror
1241 */
1242function AccessorMirror(getter, setter) {
1243 Mirror.call(this, ACCESSOR_TYPE);
1244 this.getter_ = getter;
1245 this.setter_ = setter;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001246}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247inherits(AccessorMirror, Mirror);
1248
1249
1250/**
1251 * Returns whether this accessor is native or not. A native accessor is either
1252 * a VM buildin or provided through the API. A non native accessor is defined
1253 * in JavaScript using the __defineGetter__ and/or __defineGetter__ functions.
1254 * @return {boolean} True is the accessor is native
1255 */
1256AccessorMirror.prototype.isNative = function() {
1257 return IS_UNDEFINED(this.getter_) && IS_UNDEFINED(this.setter_);
1258}
1259
1260
1261/**
1262 * Returns a mirror for the function of a non native getter.
1263 * @return {FunctionMirror} Function mirror for the getter set using
1264 * __defineGetter__.
1265 */
1266AccessorMirror.prototype.getter = function(details) {
1267 return MakeMirror(this.getter_);
1268}
1269
1270
1271/**
1272 * Returns a mirror for the function of a non native setter.
1273 * @return {FunctionMirror} Function mirror for the getter set using
1274 * __defineSetter__.
1275 */
1276AccessorMirror.prototype.setter = function(details) {
1277 return MakeMirror(this.setter_);
1278}
1279
1280
1281/**
1282 * Serialize the accessor mirror into JSON format. For accessor it has the
1283 * following format.
1284 * {"type":"accessor",
1285 "native:"<boolean>,
1286 "getter":<function mirror JSON serialization>,
1287 "setter":<function mirror JSON serialization>}
1288 * For specialized mirrors inheriting from the base Mirror
1289 * @param {boolean} details Indicate level of details to include
1290 * @return {string} JSON serialization
1291 */
1292AccessorMirror.prototype.fillJSON_ = function(content, details) {
1293 AccessorMirror.super_.fillJSONType_.call(this, content);
1294 if (this.isNative()) {
1295 content.push(MakeJSONPair_('native', BooleanToJSON_(true)));
1296 } else {
1297 content.push(MakeJSONPair_('getter', this.getter().toJSONProtocol(false)));
1298 content.push(MakeJSONPair_('setter', this.setter().toJSONProtocol(false)));
1299 }
1300}
1301
1302
1303const kFrameDetailsFrameIdIndex = 0;
1304const kFrameDetailsReceiverIndex = 1;
1305const kFrameDetailsFunctionIndex = 2;
1306const kFrameDetailsArgumentCountIndex = 3;
1307const kFrameDetailsLocalCountIndex = 4;
1308const kFrameDetailsSourcePositionIndex = 5;
1309const kFrameDetailsConstructCallIndex = 6;
1310const kFrameDetailsDebuggerFrameIndex = 7;
1311const kFrameDetailsFirstDynamicIndex = 8;
1312
1313const kFrameDetailsNameIndex = 0;
1314const kFrameDetailsValueIndex = 1;
1315const kFrameDetailsNameValueSize = 2;
1316
1317/**
1318 * Wrapper for the frame details information retreived from the VM. The frame
1319 * details from the VM is an array with the following content. See runtime.cc
1320 * Runtime_GetFrameDetails.
1321 * 0: Id
1322 * 1: Receiver
1323 * 2: Function
1324 * 3: Argument count
1325 * 4: Local count
1326 * 5: Source position
1327 * 6: Construct call
1328 * Arguments name, value
1329 * Locals name, value
1330 * @param {number} break_id Current break id
1331 * @param {number} index Frame number
1332 * @constructor
1333 */
1334function FrameDetails(break_id, index) {
1335 this.break_id_ = break_id;
1336 this.details_ = %GetFrameDetails(break_id, index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001337}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338
1339
1340FrameDetails.prototype.frameId = function() {
1341 %CheckExecutionState(this.break_id_);
1342 return this.details_[kFrameDetailsFrameIdIndex];
1343}
1344
1345
1346FrameDetails.prototype.receiver = function() {
1347 %CheckExecutionState(this.break_id_);
1348 return this.details_[kFrameDetailsReceiverIndex];
1349}
1350
1351
1352FrameDetails.prototype.func = function() {
1353 %CheckExecutionState(this.break_id_);
1354 return this.details_[kFrameDetailsFunctionIndex];
1355}
1356
1357
1358FrameDetails.prototype.isConstructCall = function() {
1359 %CheckExecutionState(this.break_id_);
1360 return this.details_[kFrameDetailsConstructCallIndex];
1361}
1362
1363
1364FrameDetails.prototype.isDebuggerFrame = function() {
1365 %CheckExecutionState(this.break_id_);
1366 return this.details_[kFrameDetailsDebuggerFrameIndex];
1367}
1368
1369
1370FrameDetails.prototype.argumentCount = function() {
1371 %CheckExecutionState(this.break_id_);
1372 return this.details_[kFrameDetailsArgumentCountIndex];
1373}
1374
1375
1376FrameDetails.prototype.argumentName = function(index) {
1377 %CheckExecutionState(this.break_id_);
1378 if (index >= 0 && index < this.argumentCount()) {
1379 return this.details_[kFrameDetailsFirstDynamicIndex +
1380 index * kFrameDetailsNameValueSize +
1381 kFrameDetailsNameIndex]
1382 }
1383}
1384
1385
1386FrameDetails.prototype.argumentValue = function(index) {
1387 %CheckExecutionState(this.break_id_);
1388 if (index >= 0 && index < this.argumentCount()) {
1389 return this.details_[kFrameDetailsFirstDynamicIndex +
1390 index * kFrameDetailsNameValueSize +
1391 kFrameDetailsValueIndex]
1392 }
1393}
1394
1395
1396FrameDetails.prototype.localCount = function() {
1397 %CheckExecutionState(this.break_id_);
1398 return this.details_[kFrameDetailsLocalCountIndex];
1399}
1400
1401
1402FrameDetails.prototype.sourcePosition = function() {
1403 %CheckExecutionState(this.break_id_);
1404 return this.details_[kFrameDetailsSourcePositionIndex];
1405}
1406
1407
1408FrameDetails.prototype.localName = function(index) {
1409 %CheckExecutionState(this.break_id_);
1410 if (index >= 0 && index < this.localCount()) {
1411 var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1412 return this.details_[locals_offset +
1413 index * kFrameDetailsNameValueSize +
1414 kFrameDetailsNameIndex]
1415 }
1416}
1417
1418
1419FrameDetails.prototype.localValue = function(index) {
1420 %CheckExecutionState(this.break_id_);
1421 if (index >= 0 && index < this.localCount()) {
1422 var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1423 return this.details_[locals_offset +
1424 index * kFrameDetailsNameValueSize +
1425 kFrameDetailsValueIndex]
1426 }
1427}
1428
1429
1430/**
1431 * Mirror object for stack frames.
1432 * @param {number} break_id The break id in the VM for which this frame is
1433 valid
1434 * @param {number} index The frame index (top frame is index 0)
1435 * @constructor
1436 * @extends Mirror
1437 */
1438function FrameMirror(break_id, index) {
1439 Mirror.call(this, FRAME_TYPE);
1440 this.break_id_ = break_id;
1441 this.index_ = index;
1442 this.details_ = new FrameDetails(break_id, index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001443}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444inherits(FrameMirror, Mirror);
1445
1446
1447FrameMirror.prototype.index = function() {
1448 return this.index_;
1449};
1450
1451
1452FrameMirror.prototype.func = function() {
1453 // Get the function for this frame from the VM.
1454 var f = this.details_.func();
1455
1456 // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1457 // value returned from the VM might be a string if the function for the
1458 // frame is unresolved.
1459 if (IS_FUNCTION(f)) {
1460 return new FunctionMirror(f);
1461 } else {
1462 return new UnresolvedFunctionMirror(f);
1463 }
1464};
1465
1466
1467FrameMirror.prototype.receiver = function() {
1468 return MakeMirror(this.details_.receiver());
1469};
1470
1471
1472FrameMirror.prototype.isConstructCall = function() {
1473 return this.details_.isConstructCall();
1474};
1475
1476
1477FrameMirror.prototype.isDebuggerFrame = function() {
1478 return this.details_.isDebuggerFrame();
1479};
1480
1481
1482FrameMirror.prototype.argumentCount = function() {
1483 return this.details_.argumentCount();
1484};
1485
1486
1487FrameMirror.prototype.argumentName = function(index) {
1488 return this.details_.argumentName(index);
1489};
1490
1491
1492FrameMirror.prototype.argumentValue = function(index) {
1493 return MakeMirror(this.details_.argumentValue(index));
1494};
1495
1496
1497FrameMirror.prototype.localCount = function() {
1498 return this.details_.localCount();
1499};
1500
1501
1502FrameMirror.prototype.localName = function(index) {
1503 return this.details_.localName(index);
1504};
1505
1506
1507FrameMirror.prototype.localValue = function(index) {
1508 return MakeMirror(this.details_.localValue(index));
1509};
1510
1511
1512FrameMirror.prototype.sourcePosition = function() {
1513 return this.details_.sourcePosition();
1514};
1515
1516
1517FrameMirror.prototype.sourceLocation = function() {
1518 if (this.func().resolved() && this.func().script()) {
1519 return this.func().script().locationFromPosition(this.sourcePosition());
1520 }
1521};
1522
1523
1524FrameMirror.prototype.sourceLine = function() {
1525 if (this.func().resolved()) {
1526 var location = this.sourceLocation();
1527 if (location) {
1528 return location.line;
1529 }
1530 }
1531};
1532
1533
1534FrameMirror.prototype.sourceColumn = function() {
1535 if (this.func().resolved()) {
1536 var location = this.sourceLocation();
1537 if (location) {
1538 return location.column;
1539 }
1540 }
1541};
1542
1543
1544FrameMirror.prototype.sourceLineText = function() {
1545 if (this.func().resolved()) {
1546 var location = this.sourceLocation();
1547 if (location) {
1548 return location.sourceText();
1549 }
1550 }
1551};
1552
1553
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001554FrameMirror.prototype.evaluate = function(source, disable_break) {
1555 var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
1556 source, Boolean(disable_break));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 return MakeMirror(result);
1558};
1559
1560
1561FrameMirror.prototype.fillJSON_ = function(content, details) {
1562 FrameMirror.super_.fillJSONType_.call(this, content);
1563 content.push(MakeJSONPair_('index', NumberToJSON_(this.index())));
1564 content.push(MakeJSONPair_('receiver', this.receiver().toJSONProtocol(false)));
1565 content.push(MakeJSONPair_('func', this.func().toJSONProtocol(false)));
1566 content.push(MakeJSONPair_('constructCall', BooleanToJSON_(this.isConstructCall())));
1567 content.push(MakeJSONPair_('debuggerFrame', BooleanToJSON_(this.isDebuggerFrame())));
1568 var x = new Array(this.argumentCount());
1569 for (var i = 0; i < this.argumentCount(); i++) {
1570 arg = new Array();
1571 var argument_name = this.argumentName(i)
1572 if (argument_name) {
1573 arg.push(MakeJSONPair_('name', StringToJSON_(argument_name)));
1574 }
1575 arg.push(MakeJSONPair_('value', this.argumentValue(i).toJSONProtocol(false)));
1576 x[i] = ArrayToJSONObject_(arg);
1577 }
1578 content.push(MakeJSONPair_('arguments', ArrayToJSONArray_(x)));
1579 var x = new Array(this.localCount());
1580 for (var i = 0; i < this.localCount(); i++) {
1581 var name = MakeJSONPair_('name', StringToJSON_(this.localName(i)));
1582 var value = MakeJSONPair_('value', this.localValue(i).toJSONProtocol(false));
1583 x[i] = '{' + name + ',' + value + '}';
1584 }
1585 content.push(MakeJSONPair_('locals', ArrayToJSONArray_(x)));
1586 content.push(MakeJSONPair_('position', NumberToJSON_(this.sourcePosition())));
1587 var line = this.sourceLine();
1588 if (!IS_UNDEFINED(line)) {
1589 content.push(MakeJSONPair_('line', NumberToJSON_(line)));
1590 }
1591 var column = this.sourceColumn();
1592 if (!IS_UNDEFINED(column)) {
1593 content.push(MakeJSONPair_('column', NumberToJSON_(column)));
1594 }
1595 var source_line_text = this.sourceLineText();
1596 if (!IS_UNDEFINED(source_line_text)) {
1597 content.push(MakeJSONPair_('sourceLineText', StringToJSON_(source_line_text)));
1598 }
1599}
1600
1601
1602FrameMirror.prototype.invocationText = function() {
1603 // Format frame invoaction (receiver, function and arguments).
1604 var result = '';
1605 var func = this.func();
1606 var receiver = this.receiver();
1607 if (this.isConstructCall()) {
1608 // For constructor frames display new followed by the function name.
1609 result += 'new ';
1610 result += func.name() ? func.name() : '[anonymous]';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001611 } else if (this.isDebuggerFrame()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 result += '[debugger]';
1613 } else {
1614 // If the receiver has a className which is 'global' don't display it.
1615 var display_receiver = !receiver.className || receiver.className() != 'global';
1616 if (display_receiver) {
1617 result += receiver.toText();
1618 }
1619 // Try to find the function as a property in the receiver. Include the
1620 // prototype chain in the lookup.
1621 var property = new UndefinedMirror();
1622 if (!receiver.isUndefined()) {
1623 for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
1624 property = r.lookupProperty(func);
1625 }
1626 }
1627 if (!property.isUndefined()) {
1628 // The function invoked was found on the receiver. Use the property name
1629 // for the backtrace.
1630 if (!property.isIndexed()) {
1631 if (display_receiver) {
1632 result += '.';
1633 }
1634 result += property.name();
1635 } else {
1636 result += '[';
1637 result += property.name();
1638 result += ']';
1639 }
1640 // Also known as - if the name in the function doesn't match the name
1641 // under which it was looked up.
1642 if (func.name() && func.name() != property.name()) {
1643 result += '(aka ' + func.name() + ')';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 } else {
1646 // The function invoked was not found on the receiver. Use the function
1647 // name if available for the backtrace.
1648 if (display_receiver) {
1649 result += '.';
1650 }
1651 result += func.name() ? func.name() : '[anonymous]';
1652 }
1653 }
1654
1655 // Render arguments for normal frames.
1656 if (!this.isDebuggerFrame()) {
1657 result += '(';
1658 for (var i = 0; i < this.argumentCount(); i++) {
1659 if (i != 0) result += ', ';
1660 if (this.argumentName(i)) {
1661 result += this.argumentName(i);
1662 result += '=';
1663 }
1664 result += this.argumentValue(i).toText();
1665 }
1666 result += ')';
1667 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 return result;
1670}
1671
1672
1673FrameMirror.prototype.sourceAndPositionText = function() {
1674 // Format source and position.
1675 var result = '';
1676 var func = this.func();
1677 if (func.resolved()) {
1678 if (func.script()) {
1679 if (func.script().name()) {
1680 result += func.script().name();
1681 } else {
1682 result += '[unnamed]';
1683 }
1684 if (!this.isDebuggerFrame()) {
1685 var location = this.sourceLocation();
1686 result += ' line ';
1687 result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1688 result += ' column ';
1689 result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1690 if (!IS_UNDEFINED(this.sourcePosition())) {
1691 result += ' (position ' + (this.sourcePosition() + 1) + ')';
1692 }
1693 }
1694 } else {
1695 result += '[no source]';
1696 }
1697 } else {
1698 result += '[unresolved]';
1699 }
1700
1701 return result;
1702}
1703
1704
1705FrameMirror.prototype.localsText = function() {
1706 // Format local variables.
1707 var result = '';
1708 var locals_count = this.localCount()
1709 if (locals_count > 0) {
1710 for (var i = 0; i < locals_count; ++i) {
1711 result += ' var ';
1712 result += this.localName(i);
1713 result += ' = ';
1714 result += this.localValue(i).toText();
1715 if (i < locals_count - 1) result += '\n';
1716 }
1717 }
1718
1719 return result;
1720}
1721
1722
1723FrameMirror.prototype.toText = function(opt_locals) {
1724 var result = '';
1725 result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1726 result += ' ';
1727 result += this.invocationText();
1728 result += ' ';
1729 result += this.sourceAndPositionText();
1730 if (opt_locals) {
1731 result += '\n';
1732 result += this.localsText();
1733 }
1734 return result;
1735}
1736
1737
1738/**
1739 * Mirror object for script source.
1740 * @param {Script} script The script object
1741 * @constructor
1742 * @extends Mirror
1743 */
1744function ScriptMirror(script) {
1745 Mirror.call(this, SCRIPT_TYPE);
1746 this.script_ = script;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001747}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748inherits(ScriptMirror, Mirror);
1749
1750
1751ScriptMirror.prototype.name = function() {
1752 return this.script_.name;
1753};
1754
1755
1756ScriptMirror.prototype.lineOffset = function() {
1757 return this.script_.line_offset;
1758};
1759
1760
1761ScriptMirror.prototype.columnOffset = function() {
1762 return this.script_.column_offset;
1763};
1764
1765
1766ScriptMirror.prototype.scriptType = function() {
1767 return this.script_.type;
1768};
1769
1770
1771ScriptMirror.prototype.lineCount = function() {
1772 return this.script_.lineCount();
1773};
1774
1775
1776ScriptMirror.prototype.locationFromPosition = function(position) {
1777 return this.script_.locationFromPosition(position);
1778}
1779
1780
1781ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1782 return this.script_.sourceSlice(opt_from_line, opt_to_line);
1783}
1784
1785
1786ScriptMirror.prototype.fillJSON_ = function(content, details) {
1787 ScriptMirror.super_.fillJSONType_.call(this, content);
1788 if (this.name()) {
1789 content.push(MakeJSONPair_('name', StringToJSON_(this.name())));
1790 }
1791 content.push(MakeJSONPair_('lineOffset', NumberToJSON_(this.lineOffset())));
1792 content.push(MakeJSONPair_('columnOffset', NumberToJSON_(this.columnOffset())));
1793 content.push(MakeJSONPair_('lineCount', NumberToJSON_(this.lineCount())));
1794 content.push(MakeJSONPair_('scriptType', NumberToJSON_(this.scriptType())));
1795}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001796
1797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798ScriptMirror.prototype.toText = function() {
1799 var result = '';
1800 result += this.name();
1801 result += ' (lines: ';
1802 if (this.lineOffset() > 0) {
1803 result += this.lineOffset();
1804 result += '-';
1805 result += this.lineOffset() + this.lineCount() - 1;
1806 } else {
1807 result += this.lineCount();
1808 }
1809 result += ')';
1810 return result;
1811}
1812
1813
1814function MakeJSONPair_(name, value) {
1815 return '"' + name + '":' + value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817
1818
1819function ArrayToJSONObject_(content) {
1820 return '{' + content.join(',') + '}';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001821}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822
1823
1824function ArrayToJSONArray_(content) {
1825 return '[' + content.join(',') + ']';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001826}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827
1828
1829function BooleanToJSON_(value) {
1830 return String(value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001831}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832
1833
1834function NumberToJSON_(value) {
1835 return String(value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001836}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837
1838
1839// Mapping of some control characters to avoid the \uXXXX syntax for most
1840// commonly used control cahracters.
1841const ctrlCharMap_ = {
1842 '\b': '\\b',
1843 '\t': '\\t',
1844 '\n': '\\n',
1845 '\f': '\\f',
1846 '\r': '\\r',
1847 '"' : '\\"',
1848 '\\': '\\\\'
1849};
1850
1851
1852// Regular expression testing for ", \ and control characters (0x00 - 0x1F).
1853const ctrlCharTest_ = new RegExp('["\\\\\x00-\x1F]');
1854
1855
1856// Regular expression matching ", \ and control characters (0x00 - 0x1F)
1857// globally.
1858const ctrlCharMatch_ = new RegExp('["\\\\\x00-\x1F]', 'g');
1859
1860
1861/**
1862 * Convert a String to its JSON representation (see http://www.json.org/). To
1863 * avoid depending on the String object this method calls the functions in
1864 * string.js directly and not through the value.
1865 * @param {String} value The String value to format as JSON
1866 * @return {string} JSON formatted String value
1867 */
1868function StringToJSON_(value) {
1869 // Check for" , \ and control characters (0x00 - 0x1F). No need to call
1870 // RegExpTest as ctrlchar is constructed using RegExp.
1871 if (ctrlCharTest_.test(value)) {
1872 // Replace ", \ and control characters (0x00 - 0x1F).
1873 return '"' +
1874 value.replace(ctrlCharMatch_, function (char) {
1875 // Use charmap if possible.
1876 var mapped = ctrlCharMap_[char];
1877 if (mapped) return mapped;
1878 mapped = char.charCodeAt();
1879 // Convert control character to unicode escape sequence.
1880 return '\\u00' +
1881 %NumberToRadixString(Math.floor(mapped / 16), 16) +
1882 %NumberToRadixString(mapped % 16, 16);
1883 })
1884 + '"';
1885 }
1886
1887 // Simple string with no special characters.
1888 return '"' + value + '"';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001889}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890
1891
1892/**
1893 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
1894 * this method calls the functions in date.js directly and not through the
1895 * value.
1896 * @param {Date} value The Date value to format as JSON
1897 * @return {string} JSON formatted Date value
1898 */
1899function DateToISO8601_(value) {
1900 function f(n) {
1901 return n < 10 ? '0' + n : n;
1902 }
1903 function g(n) {
1904 return n < 10 ? '00' + n : n < 100 ? '0' + n : n;
1905 }
1906 return builtins.GetUTCFullYearFrom(value) + '-' +
1907 f(builtins.GetUTCMonthFrom(value) + 1) + '-' +
1908 f(builtins.GetUTCDateFrom(value)) + 'T' +
1909 f(builtins.GetUTCHoursFrom(value)) + ':' +
1910 f(builtins.GetUTCMinutesFrom(value)) + ':' +
1911 f(builtins.GetUTCSecondsFrom(value)) + '.' +
1912 g(builtins.GetUTCMillisecondsFrom(value)) + 'Z';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001913}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914
1915/**
1916 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
1917 * this method calls the functions in date.js directly and not through the
1918 * value.
1919 * @param {Date} value The Date value to format as JSON
1920 * @return {string} JSON formatted Date value
1921 */
1922function DateToJSON_(value) {
1923 return '"' + DateToISO8601_(value) + '"';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001924}