blob: c43dd228ec9d12c73a0d66a4102477649f85862f [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Handle id counters.
29var next_handle_ = 0;
30var next_transient_handle_ = -1;
31
32// Mirror cache.
33var mirror_cache_ = [];
34
35
36/**
37 * Clear the mirror handle cache.
38 */
39function ClearMirrorCache() {
40 next_handle_ = 0;
41 mirror_cache_ = [];
42}
43
44
45/**
46 * Returns the mirror for a specified value or object.
47 *
48 * @param {value or Object} value the value or object to retreive the mirror for
49 * @param {boolean} transient indicate whether this object is transient and
50 * should not be added to the mirror cache. The default is not transient.
51 * @returns {Mirror} the mirror reflects the passed value or object
52 */
53function MakeMirror(value, opt_transient) {
54 var mirror;
55
56 // Look for non transient mirrors in the mirror cache.
57 if (!opt_transient) {
58 for (id in mirror_cache_) {
59 mirror = mirror_cache_[id];
60 if (mirror.value() === value) {
61 return mirror;
62 }
63 // Special check for NaN as NaN == NaN is false.
64 if (mirror.isNumber() && isNaN(mirror.value()) &&
65 typeof value == 'number' && isNaN(value)) {
66 return mirror;
67 }
68 }
69 }
Steve Block6ded16b2010-05-10 14:33:55 +010070
Andrei Popescu31002712010-02-23 13:46:05 +000071 if (IS_UNDEFINED(value)) {
72 mirror = new UndefinedMirror();
73 } else if (IS_NULL(value)) {
74 mirror = new NullMirror();
75 } else if (IS_BOOLEAN(value)) {
76 mirror = new BooleanMirror(value);
77 } else if (IS_NUMBER(value)) {
78 mirror = new NumberMirror(value);
79 } else if (IS_STRING(value)) {
80 mirror = new StringMirror(value);
81 } else if (IS_ARRAY(value)) {
82 mirror = new ArrayMirror(value);
83 } else if (IS_DATE(value)) {
84 mirror = new DateMirror(value);
85 } else if (IS_FUNCTION(value)) {
86 mirror = new FunctionMirror(value);
87 } else if (IS_REGEXP(value)) {
88 mirror = new RegExpMirror(value);
89 } else if (IS_ERROR(value)) {
90 mirror = new ErrorMirror(value);
91 } else if (IS_SCRIPT(value)) {
92 mirror = new ScriptMirror(value);
93 } else {
94 mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient);
95 }
96
97 mirror_cache_[mirror.handle()] = mirror;
98 return mirror;
99}
100
101
102/**
103 * Returns the mirror for a specified mirror handle.
104 *
105 * @param {number} handle the handle to find the mirror for
106 * @returns {Mirror or undefiend} the mirror with the requested handle or
107 * undefined if no mirror with the requested handle was found
108 */
109function LookupMirror(handle) {
110 return mirror_cache_[handle];
111}
112
Steve Block6ded16b2010-05-10 14:33:55 +0100113
Andrei Popescu31002712010-02-23 13:46:05 +0000114/**
115 * Returns the mirror for the undefined value.
116 *
117 * @returns {Mirror} the mirror reflects the undefined value
118 */
119function GetUndefinedMirror() {
120 return MakeMirror(void 0);
121}
122
123
124/**
125 * Inherit the prototype methods from one constructor into another.
126 *
127 * The Function.prototype.inherits from lang.js rewritten as a standalone
128 * function (not on Function.prototype). NOTE: If this file is to be loaded
129 * during bootstrapping this function needs to be revritten using some native
130 * functions as prototype setup using normal JavaScript does not work as
131 * expected during bootstrapping (see mirror.js in r114903).
132 *
133 * @param {function} ctor Constructor function which needs to inherit the
134 * prototype
135 * @param {function} superCtor Constructor function to inherit prototype from
136 */
137function inherits(ctor, superCtor) {
138 var tempCtor = function(){};
139 tempCtor.prototype = superCtor.prototype;
140 ctor.super_ = superCtor.prototype;
141 ctor.prototype = new tempCtor();
142 ctor.prototype.constructor = ctor;
143}
144
145
146// Type names of the different mirrors.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100147var UNDEFINED_TYPE = 'undefined';
148var NULL_TYPE = 'null';
149var BOOLEAN_TYPE = 'boolean';
150var NUMBER_TYPE = 'number';
151var STRING_TYPE = 'string';
152var OBJECT_TYPE = 'object';
153var FUNCTION_TYPE = 'function';
154var REGEXP_TYPE = 'regexp';
155var ERROR_TYPE = 'error';
156var PROPERTY_TYPE = 'property';
157var FRAME_TYPE = 'frame';
158var SCRIPT_TYPE = 'script';
159var CONTEXT_TYPE = 'context';
160var SCOPE_TYPE = 'scope';
Andrei Popescu31002712010-02-23 13:46:05 +0000161
162// Maximum length when sending strings through the JSON protocol.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100163var kMaxProtocolStringLength = 80;
Andrei Popescu31002712010-02-23 13:46:05 +0000164
165// Different kind of properties.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100166var PropertyKind = {};
Andrei Popescu31002712010-02-23 13:46:05 +0000167PropertyKind.Named = 1;
168PropertyKind.Indexed = 2;
169
170
171// A copy of the PropertyType enum from global.h
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100172var PropertyType = {};
Steve Block44f0eee2011-05-26 01:26:41 +0100173PropertyType.Normal = 0;
174PropertyType.Field = 1;
175PropertyType.ConstantFunction = 2;
176PropertyType.Callbacks = 3;
Ben Murdoch257744e2011-11-30 15:57:28 +0000177PropertyType.Handler = 4;
178PropertyType.Interceptor = 5;
179PropertyType.MapTransition = 6;
180PropertyType.ExternalArrayTransition = 7;
181PropertyType.ConstantTransition = 8;
182PropertyType.NullDescriptor = 9;
Andrei Popescu31002712010-02-23 13:46:05 +0000183
184
185// Different attributes for a property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100186var PropertyAttribute = {};
Andrei Popescu31002712010-02-23 13:46:05 +0000187PropertyAttribute.None = NONE;
188PropertyAttribute.ReadOnly = READ_ONLY;
189PropertyAttribute.DontEnum = DONT_ENUM;
190PropertyAttribute.DontDelete = DONT_DELETE;
191
192
193// A copy of the scope types from runtime.cc.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100194var ScopeType = { Global: 0,
195 Local: 1,
196 With: 2,
197 Closure: 3,
198 Catch: 4,
199 Block: 5 };
Andrei Popescu31002712010-02-23 13:46:05 +0000200
201
202// Mirror hierarchy:
203// - Mirror
204// - ValueMirror
205// - UndefinedMirror
206// - NullMirror
207// - NumberMirror
208// - StringMirror
209// - ObjectMirror
210// - FunctionMirror
211// - UnresolvedFunctionMirror
212// - ArrayMirror
213// - DateMirror
214// - RegExpMirror
215// - ErrorMirror
216// - PropertyMirror
217// - FrameMirror
218// - ScriptMirror
219
220
221/**
222 * Base class for all mirror objects.
223 * @param {string} type The type of the mirror
224 * @constructor
225 */
226function Mirror(type) {
227 this.type_ = type;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100228}
Andrei Popescu31002712010-02-23 13:46:05 +0000229
230
231Mirror.prototype.type = function() {
232 return this.type_;
233};
234
235
236/**
237 * Check whether the mirror reflects a value.
238 * @returns {boolean} True if the mirror reflects a value.
239 */
240Mirror.prototype.isValue = function() {
241 return this instanceof ValueMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100242};
Andrei Popescu31002712010-02-23 13:46:05 +0000243
244
245/**
246 * Check whether the mirror reflects the undefined value.
247 * @returns {boolean} True if the mirror reflects the undefined value.
248 */
249Mirror.prototype.isUndefined = function() {
250 return this instanceof UndefinedMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100251};
Andrei Popescu31002712010-02-23 13:46:05 +0000252
253
254/**
255 * Check whether the mirror reflects the null value.
256 * @returns {boolean} True if the mirror reflects the null value
257 */
258Mirror.prototype.isNull = function() {
259 return this instanceof NullMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260};
Andrei Popescu31002712010-02-23 13:46:05 +0000261
262
263/**
264 * Check whether the mirror reflects a boolean value.
265 * @returns {boolean} True if the mirror reflects a boolean value
266 */
267Mirror.prototype.isBoolean = function() {
268 return this instanceof BooleanMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269};
Andrei Popescu31002712010-02-23 13:46:05 +0000270
271
272/**
273 * Check whether the mirror reflects a number value.
274 * @returns {boolean} True if the mirror reflects a number value
275 */
276Mirror.prototype.isNumber = function() {
277 return this instanceof NumberMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100278};
Andrei Popescu31002712010-02-23 13:46:05 +0000279
280
281/**
282 * Check whether the mirror reflects a string value.
283 * @returns {boolean} True if the mirror reflects a string value
284 */
285Mirror.prototype.isString = function() {
286 return this instanceof StringMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100287};
Andrei Popescu31002712010-02-23 13:46:05 +0000288
289
290/**
291 * Check whether the mirror reflects an object.
292 * @returns {boolean} True if the mirror reflects an object
293 */
294Mirror.prototype.isObject = function() {
295 return this instanceof ObjectMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100296};
Andrei Popescu31002712010-02-23 13:46:05 +0000297
298
299/**
300 * Check whether the mirror reflects a function.
301 * @returns {boolean} True if the mirror reflects a function
302 */
303Mirror.prototype.isFunction = function() {
304 return this instanceof FunctionMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100305};
Andrei Popescu31002712010-02-23 13:46:05 +0000306
307
308/**
309 * Check whether the mirror reflects an unresolved function.
310 * @returns {boolean} True if the mirror reflects an unresolved function
311 */
312Mirror.prototype.isUnresolvedFunction = function() {
313 return this instanceof UnresolvedFunctionMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100314};
Andrei Popescu31002712010-02-23 13:46:05 +0000315
316
317/**
318 * Check whether the mirror reflects an array.
319 * @returns {boolean} True if the mirror reflects an array
320 */
321Mirror.prototype.isArray = function() {
322 return this instanceof ArrayMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100323};
Andrei Popescu31002712010-02-23 13:46:05 +0000324
325
326/**
327 * Check whether the mirror reflects a date.
328 * @returns {boolean} True if the mirror reflects a date
329 */
330Mirror.prototype.isDate = function() {
331 return this instanceof DateMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100332};
Andrei Popescu31002712010-02-23 13:46:05 +0000333
334
335/**
336 * Check whether the mirror reflects a regular expression.
337 * @returns {boolean} True if the mirror reflects a regular expression
338 */
339Mirror.prototype.isRegExp = function() {
340 return this instanceof RegExpMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100341};
Andrei Popescu31002712010-02-23 13:46:05 +0000342
343
344/**
345 * Check whether the mirror reflects an error.
346 * @returns {boolean} True if the mirror reflects an error
347 */
348Mirror.prototype.isError = function() {
349 return this instanceof ErrorMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100350};
Andrei Popescu31002712010-02-23 13:46:05 +0000351
352
353/**
354 * Check whether the mirror reflects a property.
355 * @returns {boolean} True if the mirror reflects a property
356 */
357Mirror.prototype.isProperty = function() {
358 return this instanceof PropertyMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100359};
Andrei Popescu31002712010-02-23 13:46:05 +0000360
361
362/**
363 * Check whether the mirror reflects a stack frame.
364 * @returns {boolean} True if the mirror reflects a stack frame
365 */
366Mirror.prototype.isFrame = function() {
367 return this instanceof FrameMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100368};
Andrei Popescu31002712010-02-23 13:46:05 +0000369
370
371/**
372 * Check whether the mirror reflects a script.
373 * @returns {boolean} True if the mirror reflects a script
374 */
375Mirror.prototype.isScript = function() {
376 return this instanceof ScriptMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100377};
Andrei Popescu31002712010-02-23 13:46:05 +0000378
379
380/**
381 * Check whether the mirror reflects a context.
382 * @returns {boolean} True if the mirror reflects a context
383 */
384Mirror.prototype.isContext = function() {
385 return this instanceof ContextMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100386};
Andrei Popescu31002712010-02-23 13:46:05 +0000387
388
389/**
390 * Check whether the mirror reflects a scope.
391 * @returns {boolean} True if the mirror reflects a scope
392 */
393Mirror.prototype.isScope = function() {
394 return this instanceof ScopeMirror;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100395};
Andrei Popescu31002712010-02-23 13:46:05 +0000396
397
398/**
399 * Allocate a handle id for this object.
400 */
401Mirror.prototype.allocateHandle_ = function() {
402 this.handle_ = next_handle_++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100403};
Andrei Popescu31002712010-02-23 13:46:05 +0000404
405
406/**
407 * Allocate a transient handle id for this object. Transient handles are
408 * negative.
409 */
410Mirror.prototype.allocateTransientHandle_ = function() {
411 this.handle_ = next_transient_handle_--;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100412};
Andrei Popescu31002712010-02-23 13:46:05 +0000413
414
415Mirror.prototype.toText = function() {
416 // Simpel to text which is used when on specialization in subclass.
Steve Block1e0659c2011-05-24 12:43:12 +0100417 return "#<" + this.constructor.name + ">";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100418};
Andrei Popescu31002712010-02-23 13:46:05 +0000419
420
421/**
422 * Base class for all value mirror objects.
423 * @param {string} type The type of the mirror
424 * @param {value} value The value reflected by this mirror
425 * @param {boolean} transient indicate whether this object is transient with a
426 * transient handle
427 * @constructor
428 * @extends Mirror
429 */
430function ValueMirror(type, value, transient) {
Steve Block1e0659c2011-05-24 12:43:12 +0100431 %_CallFunction(this, type, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000432 this.value_ = value;
433 if (!transient) {
434 this.allocateHandle_();
435 } else {
436 this.allocateTransientHandle_();
437 }
438}
439inherits(ValueMirror, Mirror);
440
441
442Mirror.prototype.handle = function() {
443 return this.handle_;
444};
445
446
447/**
448 * Check whether this is a primitive value.
449 * @return {boolean} True if the mirror reflects a primitive value
450 */
451ValueMirror.prototype.isPrimitive = function() {
452 var type = this.type();
453 return type === 'undefined' ||
454 type === 'null' ||
455 type === 'boolean' ||
456 type === 'number' ||
457 type === 'string';
458};
459
460
461/**
462 * Get the actual value reflected by this mirror.
463 * @return {value} The value reflected by this mirror
464 */
465ValueMirror.prototype.value = function() {
466 return this.value_;
467};
468
469
470/**
471 * Mirror object for Undefined.
472 * @constructor
473 * @extends ValueMirror
474 */
475function UndefinedMirror() {
Steve Block1e0659c2011-05-24 12:43:12 +0100476 %_CallFunction(this, UNDEFINED_TYPE, void 0, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000477}
478inherits(UndefinedMirror, ValueMirror);
479
480
481UndefinedMirror.prototype.toText = function() {
482 return 'undefined';
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100483};
Andrei Popescu31002712010-02-23 13:46:05 +0000484
485
486/**
487 * Mirror object for null.
488 * @constructor
489 * @extends ValueMirror
490 */
491function NullMirror() {
Steve Block1e0659c2011-05-24 12:43:12 +0100492 %_CallFunction(this, NULL_TYPE, null, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000493}
494inherits(NullMirror, ValueMirror);
495
496
497NullMirror.prototype.toText = function() {
498 return 'null';
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100499};
Andrei Popescu31002712010-02-23 13:46:05 +0000500
501
502/**
503 * Mirror object for boolean values.
504 * @param {boolean} value The boolean value reflected by this mirror
505 * @constructor
506 * @extends ValueMirror
507 */
508function BooleanMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +0100509 %_CallFunction(this, BOOLEAN_TYPE, value, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000510}
511inherits(BooleanMirror, ValueMirror);
512
513
514BooleanMirror.prototype.toText = function() {
515 return this.value_ ? 'true' : 'false';
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100516};
Andrei Popescu31002712010-02-23 13:46:05 +0000517
518
519/**
520 * Mirror object for number values.
521 * @param {number} value The number value reflected by this mirror
522 * @constructor
523 * @extends ValueMirror
524 */
525function NumberMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +0100526 %_CallFunction(this, NUMBER_TYPE, value, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000527}
528inherits(NumberMirror, ValueMirror);
529
530
531NumberMirror.prototype.toText = function() {
532 return %NumberToString(this.value_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100533};
Andrei Popescu31002712010-02-23 13:46:05 +0000534
535
536/**
537 * Mirror object for string values.
538 * @param {string} value The string value reflected by this mirror
539 * @constructor
540 * @extends ValueMirror
541 */
542function StringMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +0100543 %_CallFunction(this, STRING_TYPE, value, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000544}
545inherits(StringMirror, ValueMirror);
546
547
548StringMirror.prototype.length = function() {
549 return this.value_.length;
550};
551
Andrei Popescu402d9372010-02-26 13:31:12 +0000552StringMirror.prototype.getTruncatedValue = function(maxLength) {
553 if (maxLength != -1 && this.length() > maxLength) {
554 return this.value_.substring(0, maxLength) +
555 '... (length: ' + this.length() + ')';
556 }
557 return this.value_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100558};
Andrei Popescu31002712010-02-23 13:46:05 +0000559
560StringMirror.prototype.toText = function() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000561 return this.getTruncatedValue(kMaxProtocolStringLength);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100562};
Andrei Popescu31002712010-02-23 13:46:05 +0000563
564
565/**
566 * Mirror object for objects.
567 * @param {object} value The object reflected by this mirror
568 * @param {boolean} transient indicate whether this object is transient with a
569 * transient handle
570 * @constructor
571 * @extends ValueMirror
572 */
573function ObjectMirror(value, type, transient) {
Steve Block1e0659c2011-05-24 12:43:12 +0100574 %_CallFunction(this, type || OBJECT_TYPE, value, transient, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000575}
576inherits(ObjectMirror, ValueMirror);
577
578
579ObjectMirror.prototype.className = function() {
580 return %_ClassOf(this.value_);
581};
582
583
584ObjectMirror.prototype.constructorFunction = function() {
585 return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
586};
587
588
589ObjectMirror.prototype.prototypeObject = function() {
590 return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
591};
592
593
594ObjectMirror.prototype.protoObject = function() {
595 return MakeMirror(%DebugGetPrototype(this.value_));
596};
597
598
599ObjectMirror.prototype.hasNamedInterceptor = function() {
600 // Get information on interceptors for this object.
601 var x = %GetInterceptorInfo(this.value_);
602 return (x & 2) != 0;
603};
604
605
606ObjectMirror.prototype.hasIndexedInterceptor = function() {
607 // Get information on interceptors for this object.
608 var x = %GetInterceptorInfo(this.value_);
609 return (x & 1) != 0;
610};
611
612
613/**
614 * Return the property names for this object.
615 * @param {number} kind Indicate whether named, indexed or both kinds of
616 * properties are requested
617 * @param {number} limit Limit the number of names returend to the specified
618 value
619 * @return {Array} Property names for this object
620 */
621ObjectMirror.prototype.propertyNames = function(kind, limit) {
622 // Find kind and limit and allocate array for the result
623 kind = kind || PropertyKind.Named | PropertyKind.Indexed;
624
625 var propertyNames;
626 var elementNames;
627 var total = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100628
Andrei Popescu31002712010-02-23 13:46:05 +0000629 // Find all the named properties.
630 if (kind & PropertyKind.Named) {
631 // Get the local property names.
632 propertyNames = %GetLocalPropertyNames(this.value_);
633 total += propertyNames.length;
634
635 // Get names for named interceptor properties if any.
636 if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) {
637 var namedInterceptorNames =
638 %GetNamedInterceptorPropertyNames(this.value_);
639 if (namedInterceptorNames) {
640 propertyNames = propertyNames.concat(namedInterceptorNames);
641 total += namedInterceptorNames.length;
642 }
643 }
644 }
645
646 // Find all the indexed properties.
647 if (kind & PropertyKind.Indexed) {
648 // Get the local element names.
649 elementNames = %GetLocalElementNames(this.value_);
650 total += elementNames.length;
651
652 // Get names for indexed interceptor properties.
653 if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) {
654 var indexedInterceptorNames =
655 %GetIndexedInterceptorElementNames(this.value_);
656 if (indexedInterceptorNames) {
657 elementNames = elementNames.concat(indexedInterceptorNames);
658 total += indexedInterceptorNames.length;
659 }
660 }
661 }
662 limit = Math.min(limit || total, total);
663
664 var names = new Array(limit);
665 var index = 0;
666
667 // Copy names for named properties.
668 if (kind & PropertyKind.Named) {
669 for (var i = 0; index < limit && i < propertyNames.length; i++) {
670 names[index++] = propertyNames[i];
671 }
672 }
673
674 // Copy names for indexed properties.
675 if (kind & PropertyKind.Indexed) {
676 for (var i = 0; index < limit && i < elementNames.length; i++) {
677 names[index++] = elementNames[i];
678 }
679 }
680
681 return names;
682};
683
684
685/**
686 * Return the properties for this object as an array of PropertyMirror objects.
687 * @param {number} kind Indicate whether named, indexed or both kinds of
688 * properties are requested
689 * @param {number} limit Limit the number of properties returend to the
690 specified value
691 * @return {Array} Property mirrors for this object
692 */
693ObjectMirror.prototype.properties = function(kind, limit) {
694 var names = this.propertyNames(kind, limit);
695 var properties = new Array(names.length);
696 for (var i = 0; i < names.length; i++) {
697 properties[i] = this.property(names[i]);
698 }
699
700 return properties;
701};
702
703
704ObjectMirror.prototype.property = function(name) {
705 var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
706 if (details) {
707 return new PropertyMirror(this, name, details);
708 }
709
710 // Nothing found.
711 return GetUndefinedMirror();
712};
713
714
715
716/**
717 * Try to find a property from its value.
718 * @param {Mirror} value The property value to look for
719 * @return {PropertyMirror} The property with the specified value. If no
720 * property was found with the specified value UndefinedMirror is returned
721 */
722ObjectMirror.prototype.lookupProperty = function(value) {
723 var properties = this.properties();
724
725 // Look for property value in properties.
726 for (var i = 0; i < properties.length; i++) {
727
728 // Skip properties which are defined through assessors.
729 var property = properties[i];
730 if (property.propertyType() != PropertyType.Callbacks) {
731 if (%_ObjectEquals(property.value_, value.value_)) {
732 return property;
733 }
734 }
735 }
736
737 // Nothing found.
738 return GetUndefinedMirror();
739};
740
741
742/**
743 * Returns objects which has direct references to this object
744 * @param {number} opt_max_objects Optional parameter specifying the maximum
745 * number of referencing objects to return.
746 * @return {Array} The objects which has direct references to this object.
747 */
748ObjectMirror.prototype.referencedBy = function(opt_max_objects) {
749 // Find all objects with direct references to this object.
750 var result = %DebugReferencedBy(this.value_,
751 Mirror.prototype, opt_max_objects || 0);
752
753 // Make mirrors for all the references found.
754 for (var i = 0; i < result.length; i++) {
755 result[i] = MakeMirror(result[i]);
756 }
757
758 return result;
759};
760
761
762ObjectMirror.prototype.toText = function() {
763 var name;
764 var ctor = this.constructorFunction();
765 if (!ctor.isFunction()) {
766 name = this.className();
767 } else {
768 name = ctor.name();
769 if (!name) {
770 name = this.className();
771 }
772 }
Steve Block1e0659c2011-05-24 12:43:12 +0100773 return '#<' + name + '>';
Andrei Popescu31002712010-02-23 13:46:05 +0000774};
775
776
777/**
778 * Mirror object for functions.
779 * @param {function} value The function object reflected by this mirror.
780 * @constructor
781 * @extends ObjectMirror
782 */
783function FunctionMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +0100784 %_CallFunction(this, value, FUNCTION_TYPE, ObjectMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000785 this.resolved_ = true;
786}
787inherits(FunctionMirror, ObjectMirror);
788
789
790/**
791 * Returns whether the function is resolved.
792 * @return {boolean} True if the function is resolved. Unresolved functions can
793 * only originate as functions from stack frames
794 */
795FunctionMirror.prototype.resolved = function() {
796 return this.resolved_;
797};
798
799
800/**
801 * Returns the name of the function.
802 * @return {string} Name of the function
803 */
804FunctionMirror.prototype.name = function() {
805 return %FunctionGetName(this.value_);
806};
807
808
809/**
810 * Returns the inferred name of the function.
811 * @return {string} Name of the function
812 */
813FunctionMirror.prototype.inferredName = function() {
814 return %FunctionGetInferredName(this.value_);
815};
816
817
818/**
819 * Returns the source code for the function.
820 * @return {string or undefined} The source code for the function. If the
821 * function is not resolved undefined will be returned.
822 */
823FunctionMirror.prototype.source = function() {
824 // Return source if function is resolved. Otherwise just fall through to
825 // return undefined.
826 if (this.resolved()) {
827 return builtins.FunctionSourceString(this.value_);
828 }
829};
830
831
832/**
833 * Returns the script object for the function.
834 * @return {ScriptMirror or undefined} Script object for the function or
835 * undefined if the function has no script
836 */
837FunctionMirror.prototype.script = function() {
838 // Return script if function is resolved. Otherwise just fall through
839 // to return undefined.
840 if (this.resolved()) {
841 var script = %FunctionGetScript(this.value_);
842 if (script) {
843 return MakeMirror(script);
844 }
845 }
846};
847
848
849/**
850 * Returns the script source position for the function. Only makes sense
851 * for functions which has a script defined.
852 * @return {Number or undefined} in-script position for the function
853 */
854FunctionMirror.prototype.sourcePosition_ = function() {
855 // Return script if function is resolved. Otherwise just fall through
856 // to return undefined.
857 if (this.resolved()) {
858 return %FunctionGetScriptSourcePosition(this.value_);
859 }
860};
861
862
863/**
864 * Returns the script source location object for the function. Only makes sense
865 * for functions which has a script defined.
866 * @return {Location or undefined} in-script location for the function begin
867 */
868FunctionMirror.prototype.sourceLocation = function() {
869 if (this.resolved() && this.script()) {
870 return this.script().locationFromPosition(this.sourcePosition_(),
871 true);
872 }
873};
874
875
876/**
877 * Returns objects constructed by this function.
878 * @param {number} opt_max_instances Optional parameter specifying the maximum
879 * number of instances to return.
880 * @return {Array or undefined} The objects constructed by this function.
881 */
882FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
883 if (this.resolved()) {
884 // Find all objects constructed from this function.
885 var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
886
887 // Make mirrors for all the instances found.
888 for (var i = 0; i < result.length; i++) {
889 result[i] = MakeMirror(result[i]);
890 }
891
892 return result;
893 } else {
894 return [];
895 }
896};
897
898
899FunctionMirror.prototype.toText = function() {
900 return this.source();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100901};
Andrei Popescu31002712010-02-23 13:46:05 +0000902
903
904/**
905 * Mirror object for unresolved functions.
906 * @param {string} value The name for the unresolved function reflected by this
907 * mirror.
908 * @constructor
909 * @extends ObjectMirror
910 */
911function UnresolvedFunctionMirror(value) {
912 // Construct this using the ValueMirror as an unresolved function is not a
913 // real object but just a string.
Steve Block1e0659c2011-05-24 12:43:12 +0100914 %_CallFunction(this, FUNCTION_TYPE, value, ValueMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000915 this.propertyCount_ = 0;
916 this.elementCount_ = 0;
917 this.resolved_ = false;
918}
919inherits(UnresolvedFunctionMirror, FunctionMirror);
920
921
922UnresolvedFunctionMirror.prototype.className = function() {
923 return 'Function';
924};
925
926
927UnresolvedFunctionMirror.prototype.constructorFunction = function() {
928 return GetUndefinedMirror();
929};
930
931
932UnresolvedFunctionMirror.prototype.prototypeObject = function() {
933 return GetUndefinedMirror();
934};
935
936
937UnresolvedFunctionMirror.prototype.protoObject = function() {
938 return GetUndefinedMirror();
939};
940
941
942UnresolvedFunctionMirror.prototype.name = function() {
943 return this.value_;
944};
945
946
947UnresolvedFunctionMirror.prototype.inferredName = function() {
948 return undefined;
949};
950
951
952UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
953 return [];
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100954};
Andrei Popescu31002712010-02-23 13:46:05 +0000955
956
957/**
958 * Mirror object for arrays.
959 * @param {Array} value The Array object reflected by this mirror
960 * @constructor
961 * @extends ObjectMirror
962 */
963function ArrayMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +0100964 %_CallFunction(this, value, ObjectMirror);
Andrei Popescu31002712010-02-23 13:46:05 +0000965}
966inherits(ArrayMirror, ObjectMirror);
967
968
969ArrayMirror.prototype.length = function() {
970 return this.value_.length;
971};
972
973
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100974ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index,
975 opt_to_index) {
Andrei Popescu31002712010-02-23 13:46:05 +0000976 var from_index = opt_from_index || 0;
977 var to_index = opt_to_index || this.length() - 1;
978 if (from_index > to_index) return new Array();
979 var values = new Array(to_index - from_index + 1);
980 for (var i = from_index; i <= to_index; i++) {
981 var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
982 var value;
983 if (details) {
984 value = new PropertyMirror(this, i, details);
985 } else {
986 value = GetUndefinedMirror();
987 }
988 values[i - from_index] = value;
989 }
990 return values;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100991};
Andrei Popescu31002712010-02-23 13:46:05 +0000992
993
994/**
995 * Mirror object for dates.
996 * @param {Date} value The Date object reflected by this mirror
997 * @constructor
998 * @extends ObjectMirror
999 */
1000function DateMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +01001001 %_CallFunction(this, value, ObjectMirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001002}
1003inherits(DateMirror, ObjectMirror);
1004
1005
1006DateMirror.prototype.toText = function() {
1007 var s = JSON.stringify(this.value_);
1008 return s.substring(1, s.length - 1); // cut quotes
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001009};
Andrei Popescu31002712010-02-23 13:46:05 +00001010
1011
1012/**
1013 * Mirror object for regular expressions.
1014 * @param {RegExp} value The RegExp object reflected by this mirror
1015 * @constructor
1016 * @extends ObjectMirror
1017 */
1018function RegExpMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +01001019 %_CallFunction(this, value, REGEXP_TYPE, ObjectMirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001020}
1021inherits(RegExpMirror, ObjectMirror);
1022
1023
1024/**
1025 * Returns the source to the regular expression.
1026 * @return {string or undefined} The source to the regular expression
1027 */
1028RegExpMirror.prototype.source = function() {
1029 return this.value_.source;
1030};
1031
1032
1033/**
1034 * Returns whether this regular expression has the global (g) flag set.
1035 * @return {boolean} Value of the global flag
1036 */
1037RegExpMirror.prototype.global = function() {
1038 return this.value_.global;
1039};
1040
1041
1042/**
1043 * Returns whether this regular expression has the ignore case (i) flag set.
1044 * @return {boolean} Value of the ignore case flag
1045 */
1046RegExpMirror.prototype.ignoreCase = function() {
1047 return this.value_.ignoreCase;
1048};
1049
1050
1051/**
1052 * Returns whether this regular expression has the multiline (m) flag set.
1053 * @return {boolean} Value of the multiline flag
1054 */
1055RegExpMirror.prototype.multiline = function() {
1056 return this.value_.multiline;
1057};
1058
1059
1060RegExpMirror.prototype.toText = function() {
1061 // Simpel to text which is used when on specialization in subclass.
1062 return "/" + this.source() + "/";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001063};
Andrei Popescu31002712010-02-23 13:46:05 +00001064
1065
1066/**
1067 * Mirror object for error objects.
1068 * @param {Error} value The error object reflected by this mirror
1069 * @constructor
1070 * @extends ObjectMirror
1071 */
1072function ErrorMirror(value) {
Steve Block1e0659c2011-05-24 12:43:12 +01001073 %_CallFunction(this, value, ERROR_TYPE, ObjectMirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001074}
1075inherits(ErrorMirror, ObjectMirror);
1076
1077
1078/**
1079 * Returns the message for this eror object.
1080 * @return {string or undefined} The message for this eror object
1081 */
1082ErrorMirror.prototype.message = function() {
1083 return this.value_.message;
1084};
1085
1086
1087ErrorMirror.prototype.toText = function() {
1088 // Use the same text representation as in messages.js.
1089 var text;
1090 try {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001091 str = %_CallFunction(this.value_, builtins.ErrorToString);
Andrei Popescu31002712010-02-23 13:46:05 +00001092 } catch (e) {
Steve Block1e0659c2011-05-24 12:43:12 +01001093 str = '#<Error>';
Andrei Popescu31002712010-02-23 13:46:05 +00001094 }
1095 return str;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001096};
Andrei Popescu31002712010-02-23 13:46:05 +00001097
1098
1099/**
1100 * Base mirror object for properties.
1101 * @param {ObjectMirror} mirror The mirror object having this property
1102 * @param {string} name The name of the property
1103 * @param {Array} details Details about the property
1104 * @constructor
1105 * @extends Mirror
1106 */
1107function PropertyMirror(mirror, name, details) {
Steve Block1e0659c2011-05-24 12:43:12 +01001108 %_CallFunction(this, PROPERTY_TYPE, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001109 this.mirror_ = mirror;
1110 this.name_ = name;
1111 this.value_ = details[0];
1112 this.details_ = details[1];
1113 if (details.length > 2) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001114 this.exception_ = details[2];
Andrei Popescu31002712010-02-23 13:46:05 +00001115 this.getter_ = details[3];
1116 this.setter_ = details[4];
1117 }
1118}
1119inherits(PropertyMirror, Mirror);
1120
1121
1122PropertyMirror.prototype.isReadOnly = function() {
1123 return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001124};
Andrei Popescu31002712010-02-23 13:46:05 +00001125
1126
1127PropertyMirror.prototype.isEnum = function() {
1128 return (this.attributes() & PropertyAttribute.DontEnum) == 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001129};
Andrei Popescu31002712010-02-23 13:46:05 +00001130
1131
1132PropertyMirror.prototype.canDelete = function() {
1133 return (this.attributes() & PropertyAttribute.DontDelete) == 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001134};
Andrei Popescu31002712010-02-23 13:46:05 +00001135
1136
1137PropertyMirror.prototype.name = function() {
1138 return this.name_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001139};
Andrei Popescu31002712010-02-23 13:46:05 +00001140
1141
1142PropertyMirror.prototype.isIndexed = function() {
1143 for (var i = 0; i < this.name_.length; i++) {
1144 if (this.name_[i] < '0' || '9' < this.name_[i]) {
1145 return false;
1146 }
1147 }
1148 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001149};
Andrei Popescu31002712010-02-23 13:46:05 +00001150
1151
1152PropertyMirror.prototype.value = function() {
1153 return MakeMirror(this.value_, false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001154};
Andrei Popescu31002712010-02-23 13:46:05 +00001155
1156
1157/**
1158 * Returns whether this property value is an exception.
1159 * @return {booolean} True if this property value is an exception
1160 */
1161PropertyMirror.prototype.isException = function() {
1162 return this.exception_ ? true : false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001163};
Andrei Popescu31002712010-02-23 13:46:05 +00001164
1165
1166PropertyMirror.prototype.attributes = function() {
1167 return %DebugPropertyAttributesFromDetails(this.details_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001168};
Andrei Popescu31002712010-02-23 13:46:05 +00001169
1170
1171PropertyMirror.prototype.propertyType = function() {
1172 return %DebugPropertyTypeFromDetails(this.details_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001173};
Andrei Popescu31002712010-02-23 13:46:05 +00001174
1175
1176PropertyMirror.prototype.insertionIndex = function() {
1177 return %DebugPropertyIndexFromDetails(this.details_);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001178};
Andrei Popescu31002712010-02-23 13:46:05 +00001179
1180
1181/**
1182 * Returns whether this property has a getter defined through __defineGetter__.
1183 * @return {booolean} True if this property has a getter
1184 */
1185PropertyMirror.prototype.hasGetter = function() {
1186 return this.getter_ ? true : false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001187};
Andrei Popescu31002712010-02-23 13:46:05 +00001188
1189
1190/**
1191 * Returns whether this property has a setter defined through __defineSetter__.
1192 * @return {booolean} True if this property has a setter
1193 */
1194PropertyMirror.prototype.hasSetter = function() {
1195 return this.setter_ ? true : false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001196};
Andrei Popescu31002712010-02-23 13:46:05 +00001197
1198
1199/**
1200 * Returns the getter for this property defined through __defineGetter__.
1201 * @return {Mirror} FunctionMirror reflecting the getter function or
1202 * UndefinedMirror if there is no getter for this property
1203 */
1204PropertyMirror.prototype.getter = function() {
1205 if (this.hasGetter()) {
1206 return MakeMirror(this.getter_);
1207 } else {
1208 return GetUndefinedMirror();
1209 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001210};
Andrei Popescu31002712010-02-23 13:46:05 +00001211
1212
1213/**
1214 * Returns the setter for this property defined through __defineSetter__.
1215 * @return {Mirror} FunctionMirror reflecting the setter function or
1216 * UndefinedMirror if there is no setter for this property
1217 */
1218PropertyMirror.prototype.setter = function() {
1219 if (this.hasSetter()) {
1220 return MakeMirror(this.setter_);
1221 } else {
1222 return GetUndefinedMirror();
1223 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001224};
Andrei Popescu31002712010-02-23 13:46:05 +00001225
1226
1227/**
1228 * Returns whether this property is natively implemented by the host or a set
1229 * through JavaScript code.
Steve Block6ded16b2010-05-10 14:33:55 +01001230 * @return {boolean} True if the property is
Andrei Popescu31002712010-02-23 13:46:05 +00001231 * UndefinedMirror if there is no setter for this property
1232 */
1233PropertyMirror.prototype.isNative = function() {
1234 return (this.propertyType() == PropertyType.Interceptor) ||
1235 ((this.propertyType() == PropertyType.Callbacks) &&
1236 !this.hasGetter() && !this.hasSetter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001237};
Andrei Popescu31002712010-02-23 13:46:05 +00001238
1239
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001240var kFrameDetailsFrameIdIndex = 0;
1241var kFrameDetailsReceiverIndex = 1;
1242var kFrameDetailsFunctionIndex = 2;
1243var kFrameDetailsArgumentCountIndex = 3;
1244var kFrameDetailsLocalCountIndex = 4;
1245var kFrameDetailsSourcePositionIndex = 5;
1246var kFrameDetailsConstructCallIndex = 6;
1247var kFrameDetailsAtReturnIndex = 7;
1248var kFrameDetailsFlagsIndex = 8;
1249var kFrameDetailsFirstDynamicIndex = 9;
Andrei Popescu31002712010-02-23 13:46:05 +00001250
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001251var kFrameDetailsNameIndex = 0;
1252var kFrameDetailsValueIndex = 1;
1253var kFrameDetailsNameValueSize = 2;
Andrei Popescu31002712010-02-23 13:46:05 +00001254
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001255var kFrameDetailsFlagDebuggerFrameMask = 1 << 0;
1256var kFrameDetailsFlagOptimizedFrameMask = 1 << 1;
1257var kFrameDetailsFlagInlinedFrameIndexMask = 7 << 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001258
Andrei Popescu31002712010-02-23 13:46:05 +00001259/**
1260 * Wrapper for the frame details information retreived from the VM. The frame
1261 * details from the VM is an array with the following content. See runtime.cc
1262 * Runtime_GetFrameDetails.
1263 * 0: Id
1264 * 1: Receiver
1265 * 2: Function
1266 * 3: Argument count
1267 * 4: Local count
1268 * 5: Source position
1269 * 6: Construct call
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001270 * 7: Is at return
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001271 * 8: Flags (debugger frame, optimized frame, inlined frame index)
Andrei Popescu31002712010-02-23 13:46:05 +00001272 * Arguments name, value
1273 * Locals name, value
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001274 * Return value if any
Andrei Popescu31002712010-02-23 13:46:05 +00001275 * @param {number} break_id Current break id
1276 * @param {number} index Frame number
1277 * @constructor
1278 */
1279function FrameDetails(break_id, index) {
1280 this.break_id_ = break_id;
1281 this.details_ = %GetFrameDetails(break_id, index);
1282}
1283
1284
1285FrameDetails.prototype.frameId = function() {
1286 %CheckExecutionState(this.break_id_);
1287 return this.details_[kFrameDetailsFrameIdIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001288};
Andrei Popescu31002712010-02-23 13:46:05 +00001289
1290
1291FrameDetails.prototype.receiver = function() {
1292 %CheckExecutionState(this.break_id_);
1293 return this.details_[kFrameDetailsReceiverIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001294};
Andrei Popescu31002712010-02-23 13:46:05 +00001295
1296
1297FrameDetails.prototype.func = function() {
1298 %CheckExecutionState(this.break_id_);
1299 return this.details_[kFrameDetailsFunctionIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001300};
Andrei Popescu31002712010-02-23 13:46:05 +00001301
1302
1303FrameDetails.prototype.isConstructCall = function() {
1304 %CheckExecutionState(this.break_id_);
1305 return this.details_[kFrameDetailsConstructCallIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001306};
Andrei Popescu31002712010-02-23 13:46:05 +00001307
1308
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001309FrameDetails.prototype.isAtReturn = function() {
1310 %CheckExecutionState(this.break_id_);
1311 return this.details_[kFrameDetailsAtReturnIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001312};
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001313
1314
Andrei Popescu31002712010-02-23 13:46:05 +00001315FrameDetails.prototype.isDebuggerFrame = function() {
1316 %CheckExecutionState(this.break_id_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001317 var f = kFrameDetailsFlagDebuggerFrameMask;
1318 return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001319};
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001320
1321
1322FrameDetails.prototype.isOptimizedFrame = function() {
1323 %CheckExecutionState(this.break_id_);
1324 var f = kFrameDetailsFlagOptimizedFrameMask;
1325 return (this.details_[kFrameDetailsFlagsIndex] & f) == f;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001326};
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001327
1328
1329FrameDetails.prototype.isInlinedFrame = function() {
1330 return this.inlinedFrameIndex() > 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001331};
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001332
1333
1334FrameDetails.prototype.inlinedFrameIndex = function() {
1335 %CheckExecutionState(this.break_id_);
1336 var f = kFrameDetailsFlagInlinedFrameIndexMask;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001337 return (this.details_[kFrameDetailsFlagsIndex] & f) >> 2;
1338};
Andrei Popescu31002712010-02-23 13:46:05 +00001339
1340
1341FrameDetails.prototype.argumentCount = function() {
1342 %CheckExecutionState(this.break_id_);
1343 return this.details_[kFrameDetailsArgumentCountIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001344};
Andrei Popescu31002712010-02-23 13:46:05 +00001345
1346
1347FrameDetails.prototype.argumentName = function(index) {
1348 %CheckExecutionState(this.break_id_);
1349 if (index >= 0 && index < this.argumentCount()) {
1350 return this.details_[kFrameDetailsFirstDynamicIndex +
1351 index * kFrameDetailsNameValueSize +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001352 kFrameDetailsNameIndex];
Andrei Popescu31002712010-02-23 13:46:05 +00001353 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001354};
Andrei Popescu31002712010-02-23 13:46:05 +00001355
1356
1357FrameDetails.prototype.argumentValue = function(index) {
1358 %CheckExecutionState(this.break_id_);
1359 if (index >= 0 && index < this.argumentCount()) {
1360 return this.details_[kFrameDetailsFirstDynamicIndex +
1361 index * kFrameDetailsNameValueSize +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001362 kFrameDetailsValueIndex];
Andrei Popescu31002712010-02-23 13:46:05 +00001363 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001364};
Andrei Popescu31002712010-02-23 13:46:05 +00001365
1366
1367FrameDetails.prototype.localCount = function() {
1368 %CheckExecutionState(this.break_id_);
1369 return this.details_[kFrameDetailsLocalCountIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001370};
Andrei Popescu31002712010-02-23 13:46:05 +00001371
1372
1373FrameDetails.prototype.sourcePosition = function() {
1374 %CheckExecutionState(this.break_id_);
1375 return this.details_[kFrameDetailsSourcePositionIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001376};
Andrei Popescu31002712010-02-23 13:46:05 +00001377
1378
1379FrameDetails.prototype.localName = function(index) {
1380 %CheckExecutionState(this.break_id_);
1381 if (index >= 0 && index < this.localCount()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001382 var locals_offset = kFrameDetailsFirstDynamicIndex +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001383 this.argumentCount() * kFrameDetailsNameValueSize;
Andrei Popescu31002712010-02-23 13:46:05 +00001384 return this.details_[locals_offset +
1385 index * kFrameDetailsNameValueSize +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001386 kFrameDetailsNameIndex];
Andrei Popescu31002712010-02-23 13:46:05 +00001387 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388};
Andrei Popescu31002712010-02-23 13:46:05 +00001389
1390
1391FrameDetails.prototype.localValue = function(index) {
1392 %CheckExecutionState(this.break_id_);
1393 if (index >= 0 && index < this.localCount()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001394 var locals_offset = kFrameDetailsFirstDynamicIndex +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001395 this.argumentCount() * kFrameDetailsNameValueSize;
Andrei Popescu31002712010-02-23 13:46:05 +00001396 return this.details_[locals_offset +
1397 index * kFrameDetailsNameValueSize +
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001398 kFrameDetailsValueIndex];
Andrei Popescu31002712010-02-23 13:46:05 +00001399 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001400};
Andrei Popescu31002712010-02-23 13:46:05 +00001401
1402
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001403FrameDetails.prototype.returnValue = function() {
1404 %CheckExecutionState(this.break_id_);
1405 var return_value_offset =
1406 kFrameDetailsFirstDynamicIndex +
1407 (this.argumentCount() + this.localCount()) * kFrameDetailsNameValueSize;
1408 if (this.details_[kFrameDetailsAtReturnIndex]) {
1409 return this.details_[return_value_offset];
1410 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001411};
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001412
1413
Andrei Popescu31002712010-02-23 13:46:05 +00001414FrameDetails.prototype.scopeCount = function() {
1415 return %GetScopeCount(this.break_id_, this.frameId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001416};
Andrei Popescu31002712010-02-23 13:46:05 +00001417
1418
1419/**
1420 * Mirror object for stack frames.
1421 * @param {number} break_id The break id in the VM for which this frame is
1422 valid
1423 * @param {number} index The frame index (top frame is index 0)
1424 * @constructor
1425 * @extends Mirror
1426 */
1427function FrameMirror(break_id, index) {
Steve Block1e0659c2011-05-24 12:43:12 +01001428 %_CallFunction(this, FRAME_TYPE, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001429 this.break_id_ = break_id;
1430 this.index_ = index;
1431 this.details_ = new FrameDetails(break_id, index);
1432}
1433inherits(FrameMirror, Mirror);
1434
1435
1436FrameMirror.prototype.index = function() {
1437 return this.index_;
1438};
1439
1440
1441FrameMirror.prototype.func = function() {
1442 // Get the function for this frame from the VM.
1443 var f = this.details_.func();
Steve Block6ded16b2010-05-10 14:33:55 +01001444
Andrei Popescu31002712010-02-23 13:46:05 +00001445 // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1446 // value returned from the VM might be a string if the function for the
1447 // frame is unresolved.
1448 if (IS_FUNCTION(f)) {
1449 return MakeMirror(f);
1450 } else {
1451 return new UnresolvedFunctionMirror(f);
1452 }
1453};
1454
1455
1456FrameMirror.prototype.receiver = function() {
1457 return MakeMirror(this.details_.receiver());
1458};
1459
1460
1461FrameMirror.prototype.isConstructCall = function() {
1462 return this.details_.isConstructCall();
1463};
1464
1465
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001466FrameMirror.prototype.isAtReturn = function() {
1467 return this.details_.isAtReturn();
1468};
1469
1470
Andrei Popescu31002712010-02-23 13:46:05 +00001471FrameMirror.prototype.isDebuggerFrame = function() {
1472 return this.details_.isDebuggerFrame();
1473};
1474
1475
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001476FrameMirror.prototype.isOptimizedFrame = function() {
1477 return this.details_.isOptimizedFrame();
1478};
1479
1480
1481FrameMirror.prototype.isInlinedFrame = function() {
1482 return this.details_.isInlinedFrame();
1483};
1484
1485
1486FrameMirror.prototype.inlinedFrameIndex = function() {
1487 return this.details_.inlinedFrameIndex();
1488};
1489
1490
Andrei Popescu31002712010-02-23 13:46:05 +00001491FrameMirror.prototype.argumentCount = function() {
1492 return this.details_.argumentCount();
1493};
1494
1495
1496FrameMirror.prototype.argumentName = function(index) {
1497 return this.details_.argumentName(index);
1498};
1499
1500
1501FrameMirror.prototype.argumentValue = function(index) {
1502 return MakeMirror(this.details_.argumentValue(index));
1503};
1504
1505
1506FrameMirror.prototype.localCount = function() {
1507 return this.details_.localCount();
1508};
1509
1510
1511FrameMirror.prototype.localName = function(index) {
1512 return this.details_.localName(index);
1513};
1514
1515
1516FrameMirror.prototype.localValue = function(index) {
1517 return MakeMirror(this.details_.localValue(index));
1518};
1519
1520
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001521FrameMirror.prototype.returnValue = function() {
1522 return MakeMirror(this.details_.returnValue());
1523};
1524
1525
Andrei Popescu31002712010-02-23 13:46:05 +00001526FrameMirror.prototype.sourcePosition = function() {
1527 return this.details_.sourcePosition();
1528};
1529
1530
1531FrameMirror.prototype.sourceLocation = function() {
1532 if (this.func().resolved() && this.func().script()) {
1533 return this.func().script().locationFromPosition(this.sourcePosition(),
1534 true);
1535 }
1536};
1537
1538
1539FrameMirror.prototype.sourceLine = function() {
1540 if (this.func().resolved()) {
1541 var location = this.sourceLocation();
1542 if (location) {
1543 return location.line;
1544 }
1545 }
1546};
1547
1548
1549FrameMirror.prototype.sourceColumn = function() {
1550 if (this.func().resolved()) {
1551 var location = this.sourceLocation();
1552 if (location) {
1553 return location.column;
1554 }
1555 }
1556};
1557
1558
1559FrameMirror.prototype.sourceLineText = function() {
1560 if (this.func().resolved()) {
1561 var location = this.sourceLocation();
1562 if (location) {
1563 return location.sourceText();
1564 }
1565 }
1566};
1567
1568
1569FrameMirror.prototype.scopeCount = function() {
1570 return this.details_.scopeCount();
1571};
1572
1573
1574FrameMirror.prototype.scope = function(index) {
1575 return new ScopeMirror(this, index);
1576};
1577
1578
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001579FrameMirror.prototype.evaluate = function(source, disable_break,
1580 opt_context_object) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001581 var result = %DebugEvaluate(this.break_id_,
1582 this.details_.frameId(),
1583 this.details_.inlinedFrameIndex(),
1584 source,
1585 Boolean(disable_break),
1586 opt_context_object);
Andrei Popescu31002712010-02-23 13:46:05 +00001587 return MakeMirror(result);
1588};
1589
1590
1591FrameMirror.prototype.invocationText = function() {
1592 // Format frame invoaction (receiver, function and arguments).
1593 var result = '';
1594 var func = this.func();
1595 var receiver = this.receiver();
1596 if (this.isConstructCall()) {
1597 // For constructor frames display new followed by the function name.
1598 result += 'new ';
1599 result += func.name() ? func.name() : '[anonymous]';
1600 } else if (this.isDebuggerFrame()) {
1601 result += '[debugger]';
1602 } else {
1603 // If the receiver has a className which is 'global' don't display it.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001604 var display_receiver =
1605 !receiver.className || (receiver.className() != 'global');
Andrei Popescu31002712010-02-23 13:46:05 +00001606 if (display_receiver) {
1607 result += receiver.toText();
1608 }
1609 // Try to find the function as a property in the receiver. Include the
1610 // prototype chain in the lookup.
1611 var property = GetUndefinedMirror();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001612 if (receiver.isObject()) {
1613 for (var r = receiver;
1614 !r.isNull() && property.isUndefined();
1615 r = r.protoObject()) {
Andrei Popescu31002712010-02-23 13:46:05 +00001616 property = r.lookupProperty(func);
1617 }
1618 }
1619 if (!property.isUndefined()) {
1620 // The function invoked was found on the receiver. Use the property name
1621 // for the backtrace.
1622 if (!property.isIndexed()) {
1623 if (display_receiver) {
1624 result += '.';
1625 }
1626 result += property.name();
1627 } else {
1628 result += '[';
1629 result += property.name();
1630 result += ']';
1631 }
1632 // Also known as - if the name in the function doesn't match the name
1633 // under which it was looked up.
1634 if (func.name() && func.name() != property.name()) {
1635 result += '(aka ' + func.name() + ')';
1636 }
1637 } else {
1638 // The function invoked was not found on the receiver. Use the function
1639 // name if available for the backtrace.
1640 if (display_receiver) {
1641 result += '.';
1642 }
1643 result += func.name() ? func.name() : '[anonymous]';
1644 }
1645 }
1646
1647 // Render arguments for normal frames.
1648 if (!this.isDebuggerFrame()) {
1649 result += '(';
1650 for (var i = 0; i < this.argumentCount(); i++) {
1651 if (i != 0) result += ', ';
1652 if (this.argumentName(i)) {
1653 result += this.argumentName(i);
1654 result += '=';
1655 }
1656 result += this.argumentValue(i).toText();
1657 }
1658 result += ')';
1659 }
1660
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001661 if (this.isAtReturn()) {
1662 result += ' returning ';
1663 result += this.returnValue().toText();
1664 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001665
Andrei Popescu31002712010-02-23 13:46:05 +00001666 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001667};
Andrei Popescu31002712010-02-23 13:46:05 +00001668
1669
1670FrameMirror.prototype.sourceAndPositionText = function() {
1671 // Format source and position.
1672 var result = '';
1673 var func = this.func();
1674 if (func.resolved()) {
1675 if (func.script()) {
1676 if (func.script().name()) {
1677 result += func.script().name();
1678 } else {
1679 result += '[unnamed]';
1680 }
1681 if (!this.isDebuggerFrame()) {
1682 var location = this.sourceLocation();
1683 result += ' line ';
1684 result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1685 result += ' column ';
1686 result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1687 if (!IS_UNDEFINED(this.sourcePosition())) {
1688 result += ' (position ' + (this.sourcePosition() + 1) + ')';
1689 }
1690 }
1691 } else {
1692 result += '[no source]';
1693 }
1694 } else {
1695 result += '[unresolved]';
1696 }
1697
1698 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001699};
Andrei Popescu31002712010-02-23 13:46:05 +00001700
1701
1702FrameMirror.prototype.localsText = function() {
1703 // Format local variables.
1704 var result = '';
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001705 var locals_count = this.localCount();
Andrei Popescu31002712010-02-23 13:46:05 +00001706 if (locals_count > 0) {
1707 for (var i = 0; i < locals_count; ++i) {
1708 result += ' var ';
1709 result += this.localName(i);
1710 result += ' = ';
1711 result += this.localValue(i).toText();
1712 if (i < locals_count - 1) result += '\n';
1713 }
1714 }
1715
1716 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001717};
Andrei Popescu31002712010-02-23 13:46:05 +00001718
1719
1720FrameMirror.prototype.toText = function(opt_locals) {
1721 var result = '';
1722 result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1723 result += ' ';
1724 result += this.invocationText();
1725 result += ' ';
1726 result += this.sourceAndPositionText();
1727 if (opt_locals) {
1728 result += '\n';
1729 result += this.localsText();
1730 }
1731 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001732};
Andrei Popescu31002712010-02-23 13:46:05 +00001733
1734
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001735var kScopeDetailsTypeIndex = 0;
1736var kScopeDetailsObjectIndex = 1;
Andrei Popescu31002712010-02-23 13:46:05 +00001737
1738function ScopeDetails(frame, index) {
1739 this.break_id_ = frame.break_id_;
1740 this.details_ = %GetScopeDetails(frame.break_id_,
1741 frame.details_.frameId(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001742 frame.details_.inlinedFrameIndex(),
Andrei Popescu31002712010-02-23 13:46:05 +00001743 index);
1744}
1745
1746
1747ScopeDetails.prototype.type = function() {
1748 %CheckExecutionState(this.break_id_);
1749 return this.details_[kScopeDetailsTypeIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001750};
Andrei Popescu31002712010-02-23 13:46:05 +00001751
1752
1753ScopeDetails.prototype.object = function() {
1754 %CheckExecutionState(this.break_id_);
1755 return this.details_[kScopeDetailsObjectIndex];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001756};
Andrei Popescu31002712010-02-23 13:46:05 +00001757
1758
1759/**
1760 * Mirror object for scope.
1761 * @param {FrameMirror} frame The frame this scope is a part of
1762 * @param {number} index The scope index in the frame
1763 * @constructor
1764 * @extends Mirror
1765 */
1766function ScopeMirror(frame, index) {
Steve Block1e0659c2011-05-24 12:43:12 +01001767 %_CallFunction(this, SCOPE_TYPE, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001768 this.frame_index_ = frame.index_;
1769 this.scope_index_ = index;
1770 this.details_ = new ScopeDetails(frame, index);
1771}
1772inherits(ScopeMirror, Mirror);
1773
1774
1775ScopeMirror.prototype.frameIndex = function() {
1776 return this.frame_index_;
1777};
1778
1779
1780ScopeMirror.prototype.scopeIndex = function() {
1781 return this.scope_index_;
1782};
1783
1784
1785ScopeMirror.prototype.scopeType = function() {
1786 return this.details_.type();
1787};
1788
1789
1790ScopeMirror.prototype.scopeObject = function() {
1791 // For local and closure scopes create a transient mirror as these objects are
1792 // created on the fly materializing the local or closure scopes and
1793 // therefore will not preserve identity.
1794 var transient = this.scopeType() == ScopeType.Local ||
1795 this.scopeType() == ScopeType.Closure;
1796 return MakeMirror(this.details_.object(), transient);
1797};
1798
1799
1800/**
1801 * Mirror object for script source.
1802 * @param {Script} script The script object
1803 * @constructor
1804 * @extends Mirror
1805 */
1806function ScriptMirror(script) {
Steve Block1e0659c2011-05-24 12:43:12 +01001807 %_CallFunction(this, SCRIPT_TYPE, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001808 this.script_ = script;
1809 this.context_ = new ContextMirror(script.context_data);
1810 this.allocateHandle_();
1811}
1812inherits(ScriptMirror, Mirror);
1813
1814
1815ScriptMirror.prototype.value = function() {
1816 return this.script_;
1817};
1818
1819
1820ScriptMirror.prototype.name = function() {
Steve Block6ded16b2010-05-10 14:33:55 +01001821 return this.script_.name || this.script_.nameOrSourceURL();
Andrei Popescu31002712010-02-23 13:46:05 +00001822};
1823
1824
1825ScriptMirror.prototype.id = function() {
1826 return this.script_.id;
1827};
1828
1829
1830ScriptMirror.prototype.source = function() {
1831 return this.script_.source;
1832};
1833
1834
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001835ScriptMirror.prototype.setSource = function(source) {
1836 %DebugSetScriptSource(this.script_, source);
1837};
1838
1839
Andrei Popescu31002712010-02-23 13:46:05 +00001840ScriptMirror.prototype.lineOffset = function() {
1841 return this.script_.line_offset;
1842};
1843
1844
1845ScriptMirror.prototype.columnOffset = function() {
1846 return this.script_.column_offset;
1847};
1848
1849
1850ScriptMirror.prototype.data = function() {
1851 return this.script_.data;
1852};
1853
1854
1855ScriptMirror.prototype.scriptType = function() {
1856 return this.script_.type;
1857};
1858
1859
1860ScriptMirror.prototype.compilationType = function() {
1861 return this.script_.compilation_type;
1862};
1863
1864
1865ScriptMirror.prototype.lineCount = function() {
1866 return this.script_.lineCount();
1867};
1868
1869
1870ScriptMirror.prototype.locationFromPosition = function(
1871 position, include_resource_offset) {
1872 return this.script_.locationFromPosition(position, include_resource_offset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001873};
Andrei Popescu31002712010-02-23 13:46:05 +00001874
1875
1876ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1877 return this.script_.sourceSlice(opt_from_line, opt_to_line);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001878};
Andrei Popescu31002712010-02-23 13:46:05 +00001879
1880
1881ScriptMirror.prototype.context = function() {
1882 return this.context_;
1883};
1884
1885
1886ScriptMirror.prototype.evalFromScript = function() {
1887 return MakeMirror(this.script_.eval_from_script);
1888};
1889
1890
1891ScriptMirror.prototype.evalFromFunctionName = function() {
1892 return MakeMirror(this.script_.eval_from_function_name);
1893};
1894
1895
1896ScriptMirror.prototype.evalFromLocation = function() {
1897 var eval_from_script = this.evalFromScript();
1898 if (!eval_from_script.isUndefined()) {
1899 var position = this.script_.eval_from_script_position;
1900 return eval_from_script.locationFromPosition(position, true);
1901 }
1902};
1903
1904
1905ScriptMirror.prototype.toText = function() {
1906 var result = '';
1907 result += this.name();
1908 result += ' (lines: ';
1909 if (this.lineOffset() > 0) {
1910 result += this.lineOffset();
1911 result += '-';
1912 result += this.lineOffset() + this.lineCount() - 1;
1913 } else {
1914 result += this.lineCount();
1915 }
1916 result += ')';
1917 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001918};
Andrei Popescu31002712010-02-23 13:46:05 +00001919
1920
1921/**
1922 * Mirror object for context.
1923 * @param {Object} data The context data
1924 * @constructor
1925 * @extends Mirror
1926 */
1927function ContextMirror(data) {
Steve Block1e0659c2011-05-24 12:43:12 +01001928 %_CallFunction(this, CONTEXT_TYPE, Mirror);
Andrei Popescu31002712010-02-23 13:46:05 +00001929 this.data_ = data;
1930 this.allocateHandle_();
1931}
1932inherits(ContextMirror, Mirror);
1933
1934
1935ContextMirror.prototype.data = function() {
1936 return this.data_;
1937};
1938
1939
1940/**
1941 * Returns a mirror serializer
1942 *
1943 * @param {boolean} details Set to true to include details
1944 * @param {Object} options Options comtrolling the serialization
1945 * The following options can be set:
1946 * includeSource: include ths full source of scripts
1947 * @returns {MirrorSerializer} mirror serializer
1948 */
1949function MakeMirrorSerializer(details, options) {
1950 return new JSONProtocolSerializer(details, options);
1951}
1952
1953
1954/**
1955 * Object for serializing a mirror objects and its direct references.
1956 * @param {boolean} details Indicates whether to include details for the mirror
1957 * serialized
1958 * @constructor
1959 */
1960function JSONProtocolSerializer(details, options) {
1961 this.details_ = details;
1962 this.options_ = options;
1963 this.mirrors_ = [ ];
1964}
1965
1966
1967/**
1968 * Returns a serialization of an object reference. The referenced object are
1969 * added to the serialization state.
1970 *
1971 * @param {Mirror} mirror The mirror to serialize
1972 * @returns {String} JSON serialization
1973 */
1974JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1975 return this.serialize_(mirror, true, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001976};
Andrei Popescu31002712010-02-23 13:46:05 +00001977
1978
1979/**
1980 * Returns a serialization of an object value. The referenced objects are
1981 * added to the serialization state.
1982 *
1983 * @param {Mirror} mirror The mirror to serialize
1984 * @returns {String} JSON serialization
1985 */
1986JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1987 var json = this.serialize_(mirror, false, true);
1988 return json;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001989};
Andrei Popescu31002712010-02-23 13:46:05 +00001990
1991
1992/**
1993 * Returns a serialization of all the objects referenced.
1994 *
1995 * @param {Mirror} mirror The mirror to serialize.
1996 * @returns {Array.<Object>} Array of the referenced objects converted to
1997 * protcol objects.
1998 */
1999JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
2000 // Collect the protocol representation of the referenced objects in an array.
2001 var content = [];
Steve Block6ded16b2010-05-10 14:33:55 +01002002
Andrei Popescu31002712010-02-23 13:46:05 +00002003 // Get the number of referenced objects.
2004 var count = this.mirrors_.length;
Steve Block6ded16b2010-05-10 14:33:55 +01002005
Andrei Popescu31002712010-02-23 13:46:05 +00002006 for (var i = 0; i < count; i++) {
2007 content.push(this.serialize_(this.mirrors_[i], false, false));
2008 }
2009
2010 return content;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002011};
Andrei Popescu31002712010-02-23 13:46:05 +00002012
2013
2014JSONProtocolSerializer.prototype.includeSource_ = function() {
2015 return this.options_ && this.options_.includeSource;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002016};
Andrei Popescu31002712010-02-23 13:46:05 +00002017
2018
2019JSONProtocolSerializer.prototype.inlineRefs_ = function() {
2020 return this.options_ && this.options_.inlineRefs;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002021};
Andrei Popescu31002712010-02-23 13:46:05 +00002022
2023
Andrei Popescu402d9372010-02-26 13:31:12 +00002024JSONProtocolSerializer.prototype.maxStringLength_ = function() {
2025 if (IS_UNDEFINED(this.options_) ||
2026 IS_UNDEFINED(this.options_.maxStringLength)) {
2027 return kMaxProtocolStringLength;
2028 }
2029 return this.options_.maxStringLength;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002030};
Andrei Popescu402d9372010-02-26 13:31:12 +00002031
2032
Andrei Popescu31002712010-02-23 13:46:05 +00002033JSONProtocolSerializer.prototype.add_ = function(mirror) {
2034 // If this mirror is already in the list just return.
2035 for (var i = 0; i < this.mirrors_.length; i++) {
2036 if (this.mirrors_[i] === mirror) {
2037 return;
2038 }
2039 }
Steve Block6ded16b2010-05-10 14:33:55 +01002040
Andrei Popescu31002712010-02-23 13:46:05 +00002041 // Add the mirror to the list of mirrors to be serialized.
2042 this.mirrors_.push(mirror);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002043};
Andrei Popescu31002712010-02-23 13:46:05 +00002044
2045
2046/**
2047 * Formats mirror object to protocol reference object with some data that can
2048 * be used to display the value in debugger.
2049 * @param {Mirror} mirror Mirror to serialize.
2050 * @return {Object} Protocol reference object.
2051 */
Steve Block6ded16b2010-05-10 14:33:55 +01002052JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
Andrei Popescu31002712010-02-23 13:46:05 +00002053 function(mirror) {
2054 var o = {};
2055 o.ref = mirror.handle();
2056 o.type = mirror.type();
2057 switch (mirror.type()) {
2058 case UNDEFINED_TYPE:
2059 case NULL_TYPE:
2060 case BOOLEAN_TYPE:
2061 case NUMBER_TYPE:
2062 o.value = mirror.value();
2063 break;
2064 case STRING_TYPE:
Andrei Popescu402d9372010-02-26 13:31:12 +00002065 o.value = mirror.getTruncatedValue(this.maxStringLength_());
Andrei Popescu31002712010-02-23 13:46:05 +00002066 break;
2067 case FUNCTION_TYPE:
2068 o.name = mirror.name();
2069 o.inferredName = mirror.inferredName();
2070 if (mirror.script()) {
2071 o.scriptId = mirror.script().id();
2072 }
2073 break;
2074 case ERROR_TYPE:
2075 case REGEXP_TYPE:
2076 o.value = mirror.toText();
2077 break;
2078 case OBJECT_TYPE:
2079 o.className = mirror.className();
2080 break;
2081 }
2082 return o;
2083};
2084
2085
2086JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
2087 details) {
2088 // If serializing a reference to a mirror just return the reference and add
2089 // the mirror to the referenced mirrors.
2090 if (reference &&
2091 (mirror.isValue() || mirror.isScript() || mirror.isContext())) {
2092 if (this.inlineRefs_() && mirror.isValue()) {
2093 return this.serializeReferenceWithDisplayData_(mirror);
2094 } else {
2095 this.add_(mirror);
2096 return {'ref' : mirror.handle()};
2097 }
2098 }
Steve Block6ded16b2010-05-10 14:33:55 +01002099
Andrei Popescu31002712010-02-23 13:46:05 +00002100 // Collect the JSON property/value pairs.
2101 var content = {};
2102
2103 // Add the mirror handle.
2104 if (mirror.isValue() || mirror.isScript() || mirror.isContext()) {
2105 content.handle = mirror.handle();
2106 }
2107
2108 // Always add the type.
2109 content.type = mirror.type();
2110
2111 switch (mirror.type()) {
2112 case UNDEFINED_TYPE:
2113 case NULL_TYPE:
2114 // Undefined and null are represented just by their type.
2115 break;
2116
2117 case BOOLEAN_TYPE:
2118 // Boolean values are simply represented by their value.
2119 content.value = mirror.value();
2120 break;
2121
2122 case NUMBER_TYPE:
2123 // Number values are simply represented by their value.
2124 content.value = NumberToJSON_(mirror.value());
2125 break;
2126
2127 case STRING_TYPE:
2128 // String values might have their value cropped to keep down size.
Andrei Popescu402d9372010-02-26 13:31:12 +00002129 if (this.maxStringLength_() != -1 &&
2130 mirror.length() > this.maxStringLength_()) {
2131 var str = mirror.getTruncatedValue(this.maxStringLength_());
Andrei Popescu31002712010-02-23 13:46:05 +00002132 content.value = str;
2133 content.fromIndex = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +00002134 content.toIndex = this.maxStringLength_();
Andrei Popescu31002712010-02-23 13:46:05 +00002135 } else {
2136 content.value = mirror.value();
2137 }
2138 content.length = mirror.length();
2139 break;
2140
2141 case OBJECT_TYPE:
2142 case FUNCTION_TYPE:
2143 case ERROR_TYPE:
2144 case REGEXP_TYPE:
2145 // Add object representation.
2146 this.serializeObject_(mirror, content, details);
2147 break;
2148
2149 case PROPERTY_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002150 throw new Error('PropertyMirror cannot be serialized independeltly');
Andrei Popescu31002712010-02-23 13:46:05 +00002151 break;
2152
2153 case FRAME_TYPE:
2154 // Add object representation.
2155 this.serializeFrame_(mirror, content);
2156 break;
2157
2158 case SCOPE_TYPE:
2159 // Add object representation.
2160 this.serializeScope_(mirror, content);
2161 break;
2162
2163 case SCRIPT_TYPE:
2164 // Script is represented by id, name and source attributes.
2165 if (mirror.name()) {
2166 content.name = mirror.name();
2167 }
2168 content.id = mirror.id();
2169 content.lineOffset = mirror.lineOffset();
2170 content.columnOffset = mirror.columnOffset();
2171 content.lineCount = mirror.lineCount();
2172 if (mirror.data()) {
2173 content.data = mirror.data();
2174 }
2175 if (this.includeSource_()) {
2176 content.source = mirror.source();
2177 } else {
2178 var sourceStart = mirror.source().substring(0, 80);
2179 content.sourceStart = sourceStart;
2180 }
2181 content.sourceLength = mirror.source().length;
2182 content.scriptType = mirror.scriptType();
2183 content.compilationType = mirror.compilationType();
2184 // For compilation type eval emit information on the script from which
2185 // eval was called if a script is present.
2186 if (mirror.compilationType() == 1 &&
2187 mirror.evalFromScript()) {
2188 content.evalFromScript =
2189 this.serializeReference(mirror.evalFromScript());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002190 var evalFromLocation = mirror.evalFromLocation();
Andrei Popescu31002712010-02-23 13:46:05 +00002191 if (evalFromLocation) {
2192 content.evalFromLocation = { line: evalFromLocation.line,
2193 column: evalFromLocation.column };
2194 }
2195 if (mirror.evalFromFunctionName()) {
2196 content.evalFromFunctionName = mirror.evalFromFunctionName();
2197 }
2198 }
2199 if (mirror.context()) {
2200 content.context = this.serializeReference(mirror.context());
2201 }
2202 break;
2203
2204 case CONTEXT_TYPE:
2205 content.data = mirror.data();
2206 break;
2207 }
2208
2209 // Always add the text representation.
2210 content.text = mirror.toText();
Steve Block6ded16b2010-05-10 14:33:55 +01002211
Andrei Popescu31002712010-02-23 13:46:05 +00002212 // Create and return the JSON string.
2213 return content;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002214};
Andrei Popescu31002712010-02-23 13:46:05 +00002215
2216
2217/**
2218 * Serialize object information to the following JSON format.
2219 *
2220 * {"className":"<class name>",
2221 * "constructorFunction":{"ref":<number>},
2222 * "protoObject":{"ref":<number>},
2223 * "prototypeObject":{"ref":<number>},
2224 * "namedInterceptor":<boolean>,
2225 * "indexedInterceptor":<boolean>,
2226 * "properties":[<properties>]}
2227 */
2228JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
2229 details) {
2230 // Add general object properties.
2231 content.className = mirror.className();
2232 content.constructorFunction =
2233 this.serializeReference(mirror.constructorFunction());
2234 content.protoObject = this.serializeReference(mirror.protoObject());
2235 content.prototypeObject = this.serializeReference(mirror.prototypeObject());
2236
2237 // Add flags to indicate whether there are interceptors.
2238 if (mirror.hasNamedInterceptor()) {
2239 content.namedInterceptor = true;
2240 }
2241 if (mirror.hasIndexedInterceptor()) {
2242 content.indexedInterceptor = true;
2243 }
Steve Block6ded16b2010-05-10 14:33:55 +01002244
Andrei Popescu31002712010-02-23 13:46:05 +00002245 // Add function specific properties.
2246 if (mirror.isFunction()) {
2247 // Add function specific properties.
2248 content.name = mirror.name();
2249 if (!IS_UNDEFINED(mirror.inferredName())) {
2250 content.inferredName = mirror.inferredName();
2251 }
2252 content.resolved = mirror.resolved();
2253 if (mirror.resolved()) {
2254 content.source = mirror.source();
2255 }
2256 if (mirror.script()) {
2257 content.script = this.serializeReference(mirror.script());
2258 content.scriptId = mirror.script().id();
Steve Block6ded16b2010-05-10 14:33:55 +01002259
Andrei Popescu31002712010-02-23 13:46:05 +00002260 serializeLocationFields(mirror.sourceLocation(), content);
2261 }
2262 }
2263
2264 // Add date specific properties.
2265 if (mirror.isDate()) {
2266 // Add date specific properties.
2267 content.value = mirror.value();
2268 }
2269
2270 // Add actual properties - named properties followed by indexed properties.
2271 var propertyNames = mirror.propertyNames(PropertyKind.Named);
2272 var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
2273 var p = new Array(propertyNames.length + propertyIndexes.length);
2274 for (var i = 0; i < propertyNames.length; i++) {
2275 var propertyMirror = mirror.property(propertyNames[i]);
2276 p[i] = this.serializeProperty_(propertyMirror);
2277 if (details) {
2278 this.add_(propertyMirror.value());
2279 }
2280 }
2281 for (var i = 0; i < propertyIndexes.length; i++) {
2282 var propertyMirror = mirror.property(propertyIndexes[i]);
2283 p[propertyNames.length + i] = this.serializeProperty_(propertyMirror);
2284 if (details) {
2285 this.add_(propertyMirror.value());
2286 }
2287 }
2288 content.properties = p;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002289};
Andrei Popescu31002712010-02-23 13:46:05 +00002290
2291
2292/**
2293 * Serialize location information to the following JSON format:
2294 *
2295 * "position":"<position>",
2296 * "line":"<line>",
2297 * "column":"<column>",
Steve Block6ded16b2010-05-10 14:33:55 +01002298 *
Andrei Popescu31002712010-02-23 13:46:05 +00002299 * @param {SourceLocation} location The location to serialize, may be undefined.
2300 */
2301function serializeLocationFields (location, content) {
2302 if (!location) {
2303 return;
Steve Block6ded16b2010-05-10 14:33:55 +01002304 }
Andrei Popescu31002712010-02-23 13:46:05 +00002305 content.position = location.position;
2306 var line = location.line;
2307 if (!IS_UNDEFINED(line)) {
2308 content.line = line;
2309 }
2310 var column = location.column;
2311 if (!IS_UNDEFINED(column)) {
2312 content.column = column;
2313 }
2314}
2315
2316
2317/**
2318 * Serialize property information to the following JSON format for building the
2319 * array of properties.
2320 *
2321 * {"name":"<property name>",
2322 * "attributes":<number>,
2323 * "propertyType":<number>,
2324 * "ref":<number>}
2325 *
2326 * If the attribute for the property is PropertyAttribute.None it is not added.
2327 * If the propertyType for the property is PropertyType.Normal it is not added.
2328 * Here are a couple of examples.
2329 *
2330 * {"name":"hello","ref":1}
2331 * {"name":"length","attributes":7,"propertyType":3,"ref":2}
2332 *
2333 * @param {PropertyMirror} propertyMirror The property to serialize.
2334 * @returns {Object} Protocol object representing the property.
2335 */
2336JSONProtocolSerializer.prototype.serializeProperty_ = function(propertyMirror) {
2337 var result = {};
Steve Block6ded16b2010-05-10 14:33:55 +01002338
Andrei Popescu31002712010-02-23 13:46:05 +00002339 result.name = propertyMirror.name();
2340 var propertyValue = propertyMirror.value();
2341 if (this.inlineRefs_() && propertyValue.isValue()) {
2342 result.value = this.serializeReferenceWithDisplayData_(propertyValue);
2343 } else {
2344 if (propertyMirror.attributes() != PropertyAttribute.None) {
2345 result.attributes = propertyMirror.attributes();
2346 }
2347 if (propertyMirror.propertyType() != PropertyType.Normal) {
2348 result.propertyType = propertyMirror.propertyType();
2349 }
2350 result.ref = propertyValue.handle();
2351 }
2352 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002353};
Andrei Popescu31002712010-02-23 13:46:05 +00002354
2355
2356JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
2357 content.index = mirror.index();
2358 content.receiver = this.serializeReference(mirror.receiver());
2359 var func = mirror.func();
2360 content.func = this.serializeReference(func);
2361 if (func.script()) {
2362 content.script = this.serializeReference(func.script());
2363 }
2364 content.constructCall = mirror.isConstructCall();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002365 content.atReturn = mirror.isAtReturn();
2366 if (mirror.isAtReturn()) {
2367 content.returnValue = this.serializeReference(mirror.returnValue());
2368 }
Andrei Popescu31002712010-02-23 13:46:05 +00002369 content.debuggerFrame = mirror.isDebuggerFrame();
2370 var x = new Array(mirror.argumentCount());
2371 for (var i = 0; i < mirror.argumentCount(); i++) {
2372 var arg = {};
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002373 var argument_name = mirror.argumentName(i);
Andrei Popescu31002712010-02-23 13:46:05 +00002374 if (argument_name) {
2375 arg.name = argument_name;
2376 }
2377 arg.value = this.serializeReference(mirror.argumentValue(i));
2378 x[i] = arg;
2379 }
2380 content.arguments = x;
2381 var x = new Array(mirror.localCount());
2382 for (var i = 0; i < mirror.localCount(); i++) {
2383 var local = {};
2384 local.name = mirror.localName(i);
2385 local.value = this.serializeReference(mirror.localValue(i));
2386 x[i] = local;
2387 }
2388 content.locals = x;
2389 serializeLocationFields(mirror.sourceLocation(), content);
2390 var source_line_text = mirror.sourceLineText();
2391 if (!IS_UNDEFINED(source_line_text)) {
2392 content.sourceLineText = source_line_text;
2393 }
Steve Block6ded16b2010-05-10 14:33:55 +01002394
Andrei Popescu31002712010-02-23 13:46:05 +00002395 content.scopes = [];
2396 for (var i = 0; i < mirror.scopeCount(); i++) {
2397 var scope = mirror.scope(i);
2398 content.scopes.push({
2399 type: scope.scopeType(),
2400 index: i
2401 });
2402 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002403};
Andrei Popescu31002712010-02-23 13:46:05 +00002404
2405
2406JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) {
2407 content.index = mirror.scopeIndex();
2408 content.frameIndex = mirror.frameIndex();
2409 content.type = mirror.scopeType();
2410 content.object = this.inlineRefs_() ?
2411 this.serializeValue(mirror.scopeObject()) :
2412 this.serializeReference(mirror.scopeObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002413};
Andrei Popescu31002712010-02-23 13:46:05 +00002414
2415
2416/**
2417 * Convert a number to a protocol value. For all finite numbers the number
2418 * itself is returned. For non finite numbers NaN, Infinite and
2419 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
2420 * (not including the quotes) is returned.
2421 *
2422 * @param {number} value The number value to convert to a protocol value.
2423 * @returns {number|string} Protocol value.
2424 */
2425function NumberToJSON_(value) {
2426 if (isNaN(value)) {
2427 return 'NaN';
2428 }
Steve Block9fac8402011-05-12 15:51:54 +01002429 if (!NUMBER_IS_FINITE(value)) {
Andrei Popescu31002712010-02-23 13:46:05 +00002430 if (value > 0) {
2431 return 'Infinity';
2432 } else {
2433 return '-Infinity';
2434 }
2435 }
Steve Block6ded16b2010-05-10 14:33:55 +01002436 return value;
Andrei Popescu31002712010-02-23 13:46:05 +00002437}