The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / mirror-delay.js @ 40c0f755

History | View | Annotate | Download (55.8 KB)

1
// 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
// jsminify this file, js2c: jsmin
29

    
30
// Touch the RegExp and Date functions to make sure that date-delay.js and
31
// regexp-delay.js has been loaded. This is required as the mirrors use
32
// functions within these files through the builtins object. See the
33
// function DateToISO8601_ as an example.
34
RegExp;
35
Date;
36

    
37

    
38
var next_handle_ = 0;
39
var mirror_cache_ = [];
40

    
41
/**
42
 * Clear the mirror handle cache.
43
 */
44
function ClearMirrorCache() {
45
  next_handle_ = 0;
46
  mirror_cache_ = [];
47
}
48

    
49

    
50
/**
51
 * Returns the mirror for a specified value or object.
52
 *
53
 * @param {value or Object} value the value or object to retreive the mirror for
54
 * @returns {Mirror} the mirror reflects the passed value or object
55
 */
56
function MakeMirror(value) {
57
  var mirror;
58
  for (id in mirror_cache_) {
59
    mirror = mirror_cache_[id];
60
    if (mirror.value() === value) {
61
      return mirror;
62
    }
63
    // Special check for NaN as NaN == NaN is false.
64
    if (mirror.isNumber() && isNaN(mirror.value()) &&
65
        typeof value == 'number' && isNaN(value)) {
66
      return mirror;
67
    }
68
  }
69
  
70
  if (IS_UNDEFINED(value)) {
71
    mirror = new UndefinedMirror();
72
  } else if (IS_NULL(value)) {
73
    mirror = new NullMirror();
74
  } else if (IS_BOOLEAN(value)) {
75
    mirror = new BooleanMirror(value);
76
  } else if (IS_NUMBER(value)) {
77
    mirror = new NumberMirror(value);
78
  } else if (IS_STRING(value)) {
79
    mirror = new StringMirror(value);
80
  } else if (IS_ARRAY(value)) {
81
    mirror = new ArrayMirror(value);
82
  } else if (IS_DATE(value)) {
83
    mirror = new DateMirror(value);
84
  } else if (IS_FUNCTION(value)) {
85
    mirror = new FunctionMirror(value);
86
  } else if (IS_REGEXP(value)) {
87
    mirror = new RegExpMirror(value);
88
  } else if (IS_ERROR(value)) {
89
    mirror = new ErrorMirror(value);
90
  } else if (IS_SCRIPT(value)) {
91
    mirror = new ScriptMirror(value);
92
  } else {
93
    mirror = new ObjectMirror(value);
94
  }
95

    
96
  mirror_cache_[mirror.handle()] = mirror;
97
  return mirror;
98
}
99

    
100

    
101
/**
102
 * Returns the mirror for a specified mirror handle.
103
 *
104
 * @param {number} handle the handle to find the mirror for
105
 * @returns {Mirror or undefiend} the mirror with the requested handle or
106
 *     undefined if no mirror with the requested handle was found
107
 */
108
function LookupMirror(handle) {
109
  return mirror_cache_[handle];
110
}
111

    
112
  
113
/**
114
 * Returns the mirror for the undefined value.
115
 *
116
 * @returns {Mirror} the mirror reflects the undefined value
117
 */
118
function GetUndefinedMirror() {
119
  return MakeMirror(void 0);
120
}
121

    
122

    
123
/**
124
 * Inherit the prototype methods from one constructor into another.
125
 *
126
 * The Function.prototype.inherits from lang.js rewritten as a standalone
127
 * function (not on Function.prototype). NOTE: If this file is to be loaded
128
 * during bootstrapping this function needs to be revritten using some native
129
 * functions as prototype setup using normal JavaScript does not work as
130
 * expected during bootstrapping (see mirror.js in r114903).
131
 *
132
 * @param {function} ctor Constructor function which needs to inherit the
133
 *     prototype
134
 * @param {function} superCtor Constructor function to inherit prototype from
135
 */
136
function inherits(ctor, superCtor) {
137
  var tempCtor = function(){};
138
  tempCtor.prototype = superCtor.prototype;
139
  ctor.super_ = superCtor.prototype;
140
  ctor.prototype = new tempCtor();
141
  ctor.prototype.constructor = ctor;
142
}
143

    
144

    
145
// Type names of the different mirrors.
146
const UNDEFINED_TYPE = 'undefined';
147
const NULL_TYPE = 'null';
148
const BOOLEAN_TYPE = 'boolean';
149
const NUMBER_TYPE = 'number';
150
const STRING_TYPE = 'string';
151
const OBJECT_TYPE = 'object';
152
const FUNCTION_TYPE = 'function';
153
const REGEXP_TYPE = 'regexp';
154
const ERROR_TYPE = 'error';
155
const PROPERTY_TYPE = 'property';
156
const FRAME_TYPE = 'frame';
157
const SCRIPT_TYPE = 'script';
158

    
159
// Maximum length when sending strings through the JSON protocol.
160
const kMaxProtocolStringLength = 80;
161

    
162
// Different kind of properties.
163
PropertyKind = {};
164
PropertyKind.Named   = 1;
165
PropertyKind.Indexed = 2;
166

    
167

    
168
// A copy of the PropertyType enum from global.h
169
PropertyType = {};
170
PropertyType.Normal             = 0;
171
PropertyType.Field              = 1;
172
PropertyType.ConstantFunction   = 2;
173
PropertyType.Callbacks          = 3;
174
PropertyType.Interceptor        = 4;
175
PropertyType.MapTransition      = 5;
176
PropertyType.ConstantTransition = 6;
177
PropertyType.NullDescriptor     = 7;
178

    
179

    
180
// Different attributes for a property.
181
PropertyAttribute = {};
182
PropertyAttribute.None       = NONE;
183
PropertyAttribute.ReadOnly   = READ_ONLY;
184
PropertyAttribute.DontEnum   = DONT_ENUM;
185
PropertyAttribute.DontDelete = DONT_DELETE;
186

    
187

    
188
// Mirror hierarchy:
189
//   - Mirror
190
//     - ValueMirror
191
//       - UndefinedMirror
192
//       - NullMirror
193
//       - NumberMirror
194
//       - StringMirror
195
//       - ObjectMirror
196
//         - FunctionMirror
197
//           - UnresolvedFunctionMirror
198
//         - ArrayMirror
199
//         - DateMirror
200
//         - RegExpMirror
201
//         - ErrorMirror
202
//     - PropertyMirror
203
//     - FrameMirror
204
//     - ScriptMirror
205

    
206

    
207
/**
208
 * Base class for all mirror objects.
209
 * @param {string} type The type of the mirror
210
 * @constructor
211
 */
212
function Mirror(type) {
213
  this.type_ = type;
214
};
215

    
216

    
217
Mirror.prototype.type = function() {
218
  return this.type_;
219
};
220

    
221

    
222
/**
223
 * Check whether the mirror reflects a value.
224
 * @returns {boolean} True if the mirror reflects a value.
225
 */
226
Mirror.prototype.isValue = function() {
227
  return this instanceof ValueMirror;
228
}
229

    
230

    
231
/**
232
 * Check whether the mirror reflects the undefined value.
233
 * @returns {boolean} True if the mirror reflects the undefined value.
234
 */
235
Mirror.prototype.isUndefined = function() {
236
  return this instanceof UndefinedMirror;
237
}
238

    
239

    
240
/**
241
 * Check whether the mirror reflects the null value.
242
 * @returns {boolean} True if the mirror reflects the null value
243
 */
244
Mirror.prototype.isNull = function() {
245
  return this instanceof NullMirror;
246
}
247

    
248

    
249
/**
250
 * Check whether the mirror reflects a boolean value.
251
 * @returns {boolean} True if the mirror reflects a boolean value
252
 */
253
Mirror.prototype.isBoolean = function() {
254
  return this instanceof BooleanMirror;
255
}
256

    
257

    
258
/**
259
 * Check whether the mirror reflects a number value.
260
 * @returns {boolean} True if the mirror reflects a number value
261
 */
262
Mirror.prototype.isNumber = function() {
263
  return this instanceof NumberMirror;
264
}
265

    
266

    
267
/**
268
 * Check whether the mirror reflects a string value.
269
 * @returns {boolean} True if the mirror reflects a string value
270
 */
271
Mirror.prototype.isString = function() {
272
  return this instanceof StringMirror;
273
}
274

    
275

    
276
/**
277
 * Check whether the mirror reflects an object.
278
 * @returns {boolean} True if the mirror reflects an object
279
 */
280
Mirror.prototype.isObject = function() {
281
  return this instanceof ObjectMirror;
282
}
283

    
284

    
285
/**
286
 * Check whether the mirror reflects a function.
287
 * @returns {boolean} True if the mirror reflects a function
288
 */
289
Mirror.prototype.isFunction = function() {
290
  return this instanceof FunctionMirror;
291
}
292

    
293

    
294
/**
295
 * Check whether the mirror reflects an unresolved function.
296
 * @returns {boolean} True if the mirror reflects an unresolved function
297
 */
298
Mirror.prototype.isUnresolvedFunction = function() {
299
  return this instanceof UnresolvedFunctionMirror;
300
}
301

    
302

    
303
/**
304
 * Check whether the mirror reflects an array.
305
 * @returns {boolean} True if the mirror reflects an array
306
 */
307
Mirror.prototype.isArray = function() {
308
  return this instanceof ArrayMirror;
309
}
310

    
311

    
312
/**
313
 * Check whether the mirror reflects a date.
314
 * @returns {boolean} True if the mirror reflects a date
315
 */
316
Mirror.prototype.isDate = function() {
317
  return this instanceof DateMirror;
318
}
319

    
320

    
321
/**
322
 * Check whether the mirror reflects a regular expression.
323
 * @returns {boolean} True if the mirror reflects a regular expression
324
 */
325
Mirror.prototype.isRegExp = function() {
326
  return this instanceof RegExpMirror;
327
}
328

    
329

    
330
/**
331
 * Check whether the mirror reflects an error.
332
 * @returns {boolean} True if the mirror reflects an error
333
 */
334
Mirror.prototype.isError = function() {
335
  return this instanceof ErrorMirror;
336
}
337

    
338

    
339
/**
340
 * Check whether the mirror reflects a property.
341
 * @returns {boolean} True if the mirror reflects a property
342
 */
343
Mirror.prototype.isProperty = function() {
344
  return this instanceof PropertyMirror;
345
}
346

    
347

    
348
/**
349
 * Check whether the mirror reflects a stack frame.
350
 * @returns {boolean} True if the mirror reflects a stack frame
351
 */
352
Mirror.prototype.isFrame = function() {
353
  return this instanceof FrameMirror;
354
}
355

    
356

    
357
/**
358
 * Check whether the mirror reflects a script.
359
 * @returns {boolean} True if the mirror reflects a script
360
 */
361
Mirror.prototype.isScript = function() {
362
  return this instanceof ScriptMirror;
363
}
364

    
365

    
366
/**
367
 * Allocate a handle id for this object.
368
 */
369
Mirror.prototype.allocateHandle_ = function() {
370
  this.handle_ = next_handle_++;
371
}
372

    
373

    
374
Mirror.prototype.toText = function() {
375
  // Simpel to text which is used when on specialization in subclass.
376
  return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
377
}
378

    
379

    
380
/**
381
 * Base class for all value mirror objects.
382
 * @param {string} type The type of the mirror
383
 * @param {value} value The value reflected by this mirror
384
 * @constructor
385
 * @extends Mirror
386
 */
387
function ValueMirror(type, value) {
388
  Mirror.call(this, type);
389
  this.value_ = value;
390
  this.allocateHandle_();
391
}
392
inherits(ValueMirror, Mirror);
393

    
394

    
395
Mirror.prototype.handle = function() {
396
  return this.handle_;
397
};
398

    
399

    
400
/**
401
 * Check whether this is a primitive value.
402
 * @return {boolean} True if the mirror reflects a primitive value
403
 */
404
ValueMirror.prototype.isPrimitive = function() {
405
  var type = this.type();
406
  return type === 'undefined' ||
407
         type === 'null' ||
408
         type === 'boolean' ||
409
         type === 'number' ||
410
         type === 'string';
411
};
412

    
413

    
414
/**
415
 * Get the actual value reflected by this mirror.
416
 * @return {value} The value reflected by this mirror
417
 */
418
ValueMirror.prototype.value = function() {
419
  return this.value_;
420
};
421

    
422

    
423
/**
424
 * Mirror object for Undefined.
425
 * @constructor
426
 * @extends ValueMirror
427
 */
428
function UndefinedMirror() {
429
  ValueMirror.call(this, UNDEFINED_TYPE, void 0);
430
}
431
inherits(UndefinedMirror, ValueMirror);
432

    
433

    
434
UndefinedMirror.prototype.toText = function() {
435
  return 'undefined';
436
}
437

    
438

    
439
/**
440
 * Mirror object for null.
441
 * @constructor
442
 * @extends ValueMirror
443
 */
444
function NullMirror() {
445
  ValueMirror.call(this, NULL_TYPE, null);
446
}
447
inherits(NullMirror, ValueMirror);
448

    
449

    
450
NullMirror.prototype.toText = function() {
451
  return 'null';
452
}
453

    
454

    
455
/**
456
 * Mirror object for boolean values.
457
 * @param {boolean} value The boolean value reflected by this mirror
458
 * @constructor
459
 * @extends ValueMirror
460
 */
461
function BooleanMirror(value) {
462
  ValueMirror.call(this, BOOLEAN_TYPE, value);
463
}
464
inherits(BooleanMirror, ValueMirror);
465

    
466

    
467
BooleanMirror.prototype.toText = function() {
468
  return this.value_ ? 'true' : 'false';
469
}
470

    
471

    
472
/**
473
 * Mirror object for number values.
474
 * @param {number} value The number value reflected by this mirror
475
 * @constructor
476
 * @extends ValueMirror
477
 */
478
function NumberMirror(value) {
479
  ValueMirror.call(this, NUMBER_TYPE, value);
480
}
481
inherits(NumberMirror, ValueMirror);
482

    
483

    
484
NumberMirror.prototype.toText = function() {
485
  return %NumberToString(this.value_);
486
}
487

    
488

    
489
/**
490
 * Mirror object for string values.
491
 * @param {string} value The string value reflected by this mirror
492
 * @constructor
493
 * @extends ValueMirror
494
 */
495
function StringMirror(value) {
496
  ValueMirror.call(this, STRING_TYPE, value);
497
}
498
inherits(StringMirror, ValueMirror);
499

    
500

    
501
StringMirror.prototype.length = function() {
502
  return this.value_.length;
503
};
504

    
505

    
506
StringMirror.prototype.toText = function() {
507
  if (this.length() > kMaxProtocolStringLength) {
508
    return this.value_.substring(0, kMaxProtocolStringLength) +
509
           '... (length: ' + this.length() + ')';
510
  } else {
511
    return this.value_;
512
  }
513
}
514

    
515

    
516
/**
517
 * Mirror object for objects.
518
 * @param {object} value The object reflected by this mirror
519
 * @constructor
520
 * @extends ValueMirror
521
 */
522
function ObjectMirror(value, type) {
523
  ValueMirror.call(this, type || OBJECT_TYPE, value);
524
}
525
inherits(ObjectMirror, ValueMirror);
526

    
527

    
528
ObjectMirror.prototype.className = function() {
529
  return %ClassOf(this.value_);
530
};
531

    
532

    
533
ObjectMirror.prototype.constructorFunction = function() {
534
  return MakeMirror(%DebugGetProperty(this.value_, 'constructor'));
535
};
536

    
537

    
538
ObjectMirror.prototype.prototypeObject = function() {
539
  return MakeMirror(%DebugGetProperty(this.value_, 'prototype'));
540
};
541

    
542

    
543
ObjectMirror.prototype.protoObject = function() {
544
  return MakeMirror(%DebugGetPrototype(this.value_));
545
};
546

    
547

    
548
ObjectMirror.prototype.hasNamedInterceptor = function() {
549
  // Get information on interceptors for this object.
550
  var x = %DebugInterceptorInfo(this.value_);
551
  return (x & 2) != 0;
552
};
553

    
554

    
555
ObjectMirror.prototype.hasIndexedInterceptor = function() {
556
  // Get information on interceptors for this object.
557
  var x = %DebugInterceptorInfo(this.value_);
558
  return (x & 1) != 0;
559
};
560

    
561

    
562
/**
563
 * Return the property names for this object.
564
 * @param {number} kind Indicate whether named, indexed or both kinds of
565
 *     properties are requested
566
 * @param {number} limit Limit the number of names returend to the specified
567
       value
568
 * @return {Array} Property names for this object
569
 */
570
ObjectMirror.prototype.propertyNames = function(kind, limit) {
571
  // Find kind and limit and allocate array for the result
572
  kind = kind || PropertyKind.Named | PropertyKind.Indexed;
573

    
574
  var propertyNames;
575
  var elementNames;
576
  var total = 0;
577
  
578
  // Find all the named properties.
579
  if (kind & PropertyKind.Named) {
580
    // Get the local property names.
581
    propertyNames = %DebugLocalPropertyNames(this.value_);
582
    total += propertyNames.length;
583

    
584
    // Get names for named interceptor properties if any.
585
    if (this.hasNamedInterceptor() && (kind & PropertyKind.Named)) {
586
      var namedInterceptorNames =
587
          %DebugNamedInterceptorPropertyNames(this.value_);
588
      if (namedInterceptorNames) {
589
        propertyNames = propertyNames.concat(namedInterceptorNames);
590
        total += namedInterceptorNames.length;
591
      }
592
    }
593
  }
594

    
595
  // Find all the indexed properties.
596
  if (kind & PropertyKind.Indexed) {
597
    // Get the local element names.
598
    elementNames = %DebugLocalElementNames(this.value_);
599
    total += elementNames.length;
600

    
601
    // Get names for indexed interceptor properties.
602
    if (this.hasIndexedInterceptor() && (kind & PropertyKind.Indexed)) {
603
      var indexedInterceptorNames =
604
          %DebugIndexedInterceptorElementNames(this.value_);
605
      if (indexedInterceptorNames) {
606
        elementNames = elementNames.concat(indexedInterceptorNames);
607
        total += indexedInterceptorNames.length;
608
      }
609
    }
610
  }
611
  limit = Math.min(limit || total, total);
612

    
613
  var names = new Array(limit);
614
  var index = 0;
615

    
616
  // Copy names for named properties.
617
  if (kind & PropertyKind.Named) {
618
    for (var i = 0; index < limit && i < propertyNames.length; i++) {
619
      names[index++] = propertyNames[i];
620
    }
621
  }
622

    
623
  // Copy names for indexed properties.
624
  if (kind & PropertyKind.Indexed) {
625
    for (var i = 0; index < limit && i < elementNames.length; i++) {
626
      names[index++] = elementNames[i];
627
    }
628
  }
629

    
630
  return names;
631
};
632

    
633

    
634
/**
635
 * Return the properties for this object as an array of PropertyMirror objects.
636
 * @param {number} kind Indicate whether named, indexed or both kinds of
637
 *     properties are requested
638
 * @param {number} limit Limit the number of properties returend to the
639
       specified value
640
 * @return {Array} Property mirrors for this object
641
 */
642
ObjectMirror.prototype.properties = function(kind, limit) {
643
  var names = this.propertyNames(kind, limit);
644
  var properties = new Array(names.length);
645
  for (var i = 0; i < names.length; i++) {
646
    properties[i] = this.property(names[i]);
647
  }
648

    
649
  return properties;
650
};
651

    
652

    
653
ObjectMirror.prototype.property = function(name) {
654
  var details = %DebugGetPropertyDetails(this.value_, %ToString(name));
655
  if (details) {
656
    return new PropertyMirror(this, name, details);
657
  }
658

    
659
  // Nothing found.
660
  return GetUndefinedMirror();
661
};
662

    
663

    
664

    
665
/**
666
 * Try to find a property from its value.
667
 * @param {Mirror} value The property value to look for
668
 * @return {PropertyMirror} The property with the specified value. If no
669
 *     property was found with the specified value UndefinedMirror is returned
670
 */
671
ObjectMirror.prototype.lookupProperty = function(value) {
672
  var properties = this.properties();
673

    
674
  // Look for property value in properties.
675
  for (var i = 0; i < properties.length; i++) {
676

    
677
    // Skip properties which are defined through assessors.
678
    var property = properties[i];
679
    if (property.propertyType() != PropertyType.Callbacks) {
680
      if (%_ObjectEquals(property.value_, value.value_)) {
681
        return property;
682
      }
683
    }
684
  }
685

    
686
  // Nothing found.
687
  return GetUndefinedMirror();
688
};
689

    
690

    
691
/**
692
 * Returns objects which has direct references to this object
693
 * @param {number} opt_max_objects Optional parameter specifying the maximum
694
 *     number of referencing objects to return.
695
 * @return {Array} The objects which has direct references to this object.
696
 */
697
ObjectMirror.prototype.referencedBy = function(opt_max_objects) {
698
  // Find all objects with direct references to this object.
699
  var result = %DebugReferencedBy(this.value_,
700
                                  Mirror.prototype, opt_max_objects || 0);
701

    
702
  // Make mirrors for all the references found.
703
  for (var i = 0; i < result.length; i++) {
704
    result[i] = MakeMirror(result[i]);
705
  }
706

    
707
  return result;
708
};
709

    
710

    
711
ObjectMirror.prototype.toText = function() {
712
  var name;
713
  var ctor = this.constructorFunction();
714
  if (ctor.isUndefined()) {
715
    name = this.className();
716
  } else {
717
    name = ctor.name();
718
    if (!name) {
719
      name = this.className();
720
    }
721
  }
722
  return '#<' + builtins.GetInstanceName(name) + '>';
723
};
724

    
725

    
726
/**
727
 * Mirror object for functions.
728
 * @param {function} value The function object reflected by this mirror.
729
 * @constructor
730
 * @extends ObjectMirror
731
 */
732
function FunctionMirror(value) {
733
  ObjectMirror.call(this, value, FUNCTION_TYPE);
734
  this.resolved_ = true;
735
}
736
inherits(FunctionMirror, ObjectMirror);
737

    
738

    
739
/**
740
 * Returns whether the function is resolved.
741
 * @return {boolean} True if the function is resolved. Unresolved functions can
742
 *     only originate as functions from stack frames
743
 */
744
FunctionMirror.prototype.resolved = function() {
745
  return this.resolved_;
746
};
747

    
748

    
749
/**
750
 * Returns the name of the function.
751
 * @return {string} Name of the function
752
 */
753
FunctionMirror.prototype.name = function() {
754
  return %FunctionGetName(this.value_);
755
};
756

    
757

    
758
/**
759
 * Returns the source code for the function.
760
 * @return {string or undefined} The source code for the function. If the
761
 *     function is not resolved undefined will be returned.
762
 */
763
FunctionMirror.prototype.source = function() {
764
  // Return source if function is resolved. Otherwise just fall through to
765
  // return undefined.
766
  if (this.resolved()) {
767
    return builtins.FunctionSourceString(this.value_);
768
  }
769
};
770

    
771

    
772
/**
773
 * Returns the script object for the function.
774
 * @return {ScriptMirror or undefined} Script object for the function or
775
 *     undefined if the function has no script
776
 */
777
FunctionMirror.prototype.script = function() {
778
  // Return script if function is resolved. Otherwise just fall through
779
  // to return undefined.
780
  if (this.resolved()) {
781
    var script = %FunctionGetScript(this.value_);
782
    if (script) {
783
      return MakeMirror(script);
784
    }
785
  }
786
};
787

    
788

    
789
/**
790
 * Returns objects constructed by this function.
791
 * @param {number} opt_max_instances Optional parameter specifying the maximum
792
 *     number of instances to return.
793
 * @return {Array or undefined} The objects constructed by this function.
794
 */
795
FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
796
  if (this.resolved()) {
797
    // Find all objects constructed from this function.
798
    var result = %DebugConstructedBy(this.value_, opt_max_instances || 0);
799

    
800
    // Make mirrors for all the instances found.
801
    for (var i = 0; i < result.length; i++) {
802
      result[i] = MakeMirror(result[i]);
803
    }
804

    
805
    return result;
806
  } else {
807
    return [];
808
  }
809
};
810

    
811

    
812
FunctionMirror.prototype.toText = function() {
813
  return this.source();
814
}
815

    
816

    
817
/**
818
 * Mirror object for unresolved functions.
819
 * @param {string} value The name for the unresolved function reflected by this
820
 *     mirror.
821
 * @constructor
822
 * @extends ObjectMirror
823
 */
824
function UnresolvedFunctionMirror(value) {
825
  // Construct this using the ValueMirror as an unresolved function is not a
826
  // real object but just a string.
827
  ValueMirror.call(this, FUNCTION_TYPE, value);
828
  this.propertyCount_ = 0;
829
  this.elementCount_ = 0;
830
  this.resolved_ = false;
831
}
832
inherits(UnresolvedFunctionMirror, FunctionMirror);
833

    
834

    
835
UnresolvedFunctionMirror.prototype.className = function() {
836
  return 'Function';
837
};
838

    
839

    
840
UnresolvedFunctionMirror.prototype.constructorFunction = function() {
841
  return GetUndefinedMirror();
842
};
843

    
844

    
845
UnresolvedFunctionMirror.prototype.prototypeObject = function() {
846
  return GetUndefinedMirror();
847
};
848

    
849

    
850
UnresolvedFunctionMirror.prototype.protoObject = function() {
851
  return GetUndefinedMirror();
852
};
853

    
854

    
855
UnresolvedFunctionMirror.prototype.name = function() {
856
  return this.value_;
857
};
858

    
859

    
860
UnresolvedFunctionMirror.prototype.propertyNames = function(kind, limit) {
861
  return [];
862
}
863

    
864

    
865
/**
866
 * Mirror object for arrays.
867
 * @param {Array} value The Array object reflected by this mirror
868
 * @constructor
869
 * @extends ObjectMirror
870
 */
871
function ArrayMirror(value) {
872
  ObjectMirror.call(this, value);
873
}
874
inherits(ArrayMirror, ObjectMirror);
875

    
876

    
877
ArrayMirror.prototype.length = function() {
878
  return this.value_.length;
879
};
880

    
881

    
882
ArrayMirror.prototype.indexedPropertiesFromRange = function(opt_from_index, opt_to_index) {
883
  var from_index = opt_from_index || 0;
884
  var to_index = opt_to_index || this.length() - 1;
885
  if (from_index > to_index) return new Array();
886
  var values = new Array(to_index - from_index + 1);
887
  for (var i = from_index; i <= to_index; i++) {
888
    var details = %DebugGetPropertyDetails(this.value_, %ToString(i));
889
    var value;
890
    if (details) {
891
      value = new PropertyMirror(this, i, details);
892
    } else {
893
      value = GetUndefinedMirror();
894
    }
895
    values[i - from_index] = value;
896
  }
897
  return values;
898
}
899

    
900

    
901
/**
902
 * Mirror object for dates.
903
 * @param {Date} value The Date object reflected by this mirror
904
 * @constructor
905
 * @extends ObjectMirror
906
 */
907
function DateMirror(value) {
908
  ObjectMirror.call(this, value);
909
}
910
inherits(DateMirror, ObjectMirror);
911

    
912

    
913
DateMirror.prototype.toText = function() {
914
  return DateToISO8601_(this.value_);
915
}
916

    
917

    
918
/**
919
 * Mirror object for regular expressions.
920
 * @param {RegExp} value The RegExp object reflected by this mirror
921
 * @constructor
922
 * @extends ObjectMirror
923
 */
924
function RegExpMirror(value) {
925
  ObjectMirror.call(this, value, REGEXP_TYPE);
926
}
927
inherits(RegExpMirror, ObjectMirror);
928

    
929

    
930
/**
931
 * Returns the source to the regular expression.
932
 * @return {string or undefined} The source to the regular expression
933
 */
934
RegExpMirror.prototype.source = function() {
935
  return this.value_.source;
936
};
937

    
938

    
939
/**
940
 * Returns whether this regular expression has the global (g) flag set.
941
 * @return {boolean} Value of the global flag
942
 */
943
RegExpMirror.prototype.global = function() {
944
  return this.value_.global;
945
};
946

    
947

    
948
/**
949
 * Returns whether this regular expression has the ignore case (i) flag set.
950
 * @return {boolean} Value of the ignore case flag
951
 */
952
RegExpMirror.prototype.ignoreCase = function() {
953
  return this.value_.ignoreCase;
954
};
955

    
956

    
957
/**
958
 * Returns whether this regular expression has the multiline (m) flag set.
959
 * @return {boolean} Value of the multiline flag
960
 */
961
RegExpMirror.prototype.multiline = function() {
962
  return this.value_.multiline;
963
};
964

    
965

    
966
RegExpMirror.prototype.toText = function() {
967
  // Simpel to text which is used when on specialization in subclass.
968
  return "/" + this.source() + "/";
969
}
970

    
971

    
972
/**
973
 * Mirror object for error objects.
974
 * @param {Error} value The error object reflected by this mirror
975
 * @constructor
976
 * @extends ObjectMirror
977
 */
978
function ErrorMirror(value) {
979
  ObjectMirror.call(this, value, ERROR_TYPE);
980
}
981
inherits(ErrorMirror, ObjectMirror);
982

    
983

    
984
/**
985
 * Returns the message for this eror object.
986
 * @return {string or undefined} The message for this eror object
987
 */
988
ErrorMirror.prototype.message = function() {
989
  return this.value_.message;
990
};
991

    
992

    
993
ErrorMirror.prototype.toText = function() {
994
  // Use the same text representation as in messages.js.
995
  var text;
996
  try {
997
    str = builtins.ToDetailString(this.value_);
998
  } catch (e) {
999
    str = '#<an Error>';
1000
  }
1001
  return str;
1002
}
1003

    
1004

    
1005
/**
1006
 * Base mirror object for properties.
1007
 * @param {ObjectMirror} mirror The mirror object having this property
1008
 * @param {string} name The name of the property
1009
 * @param {Array} details Details about the property
1010
 * @constructor
1011
 * @extends Mirror
1012
 */
1013
function PropertyMirror(mirror, name, details) {
1014
  Mirror.call(this, PROPERTY_TYPE);
1015
  this.mirror_ = mirror;
1016
  this.name_ = name;
1017
  this.value_ = details[0];
1018
  this.details_ = details[1];
1019
  if (details.length > 2) {
1020
    this.exception_ = details[2]
1021
    this.getter_ = details[3];
1022
    this.setter_ = details[4];
1023
  }
1024
}
1025
inherits(PropertyMirror, Mirror);
1026

    
1027

    
1028
PropertyMirror.prototype.isReadOnly = function() {
1029
  return (this.attributes() & PropertyAttribute.ReadOnly) != 0;
1030
}
1031

    
1032

    
1033
PropertyMirror.prototype.isEnum = function() {
1034
  return (this.attributes() & PropertyAttribute.DontEnum) == 0;
1035
}
1036

    
1037

    
1038
PropertyMirror.prototype.canDelete = function() {
1039
  return (this.attributes() & PropertyAttribute.DontDelete) == 0;
1040
}
1041

    
1042

    
1043
PropertyMirror.prototype.name = function() {
1044
  return this.name_;
1045
}
1046

    
1047

    
1048
PropertyMirror.prototype.isIndexed = function() {
1049
  for (var i = 0; i < this.name_.length; i++) {
1050
    if (this.name_[i] < '0' || '9' < this.name_[i]) {
1051
      return false;
1052
    }
1053
  }
1054
  return true;
1055
}
1056

    
1057

    
1058
PropertyMirror.prototype.value = function() {
1059
  return MakeMirror(this.value_);
1060
}
1061

    
1062

    
1063
/**
1064
 * Returns whether this property value is an exception.
1065
 * @return {booolean} True if this property value is an exception
1066
 */
1067
PropertyMirror.prototype.isException = function() {
1068
  return this.exception_ ? true : false;
1069
}
1070

    
1071

    
1072
PropertyMirror.prototype.attributes = function() {
1073
  return %DebugPropertyAttributesFromDetails(this.details_);
1074
}
1075

    
1076

    
1077
PropertyMirror.prototype.propertyType = function() {
1078
  return %DebugPropertyTypeFromDetails(this.details_);
1079
}
1080

    
1081

    
1082
PropertyMirror.prototype.insertionIndex = function() {
1083
  return %DebugPropertyIndexFromDetails(this.details_);
1084
}
1085

    
1086

    
1087
/**
1088
 * Returns whether this property has a getter defined through __defineGetter__.
1089
 * @return {booolean} True if this property has a getter
1090
 */
1091
PropertyMirror.prototype.hasGetter = function() {
1092
  return this.getter_ ? true : false;
1093
}
1094

    
1095

    
1096
/**
1097
 * Returns whether this property has a setter defined through __defineSetter__.
1098
 * @return {booolean} True if this property has a setter
1099
 */
1100
PropertyMirror.prototype.hasSetter = function() {
1101
  return this.setter_ ? true : false;
1102
}
1103

    
1104

    
1105
/**
1106
 * Returns the getter for this property defined through __defineGetter__.
1107
 * @return {Mirror} FunctionMirror reflecting the getter function or
1108
 *     UndefinedMirror if there is no getter for this property
1109
 */
1110
PropertyMirror.prototype.getter = function() {
1111
  if (this.hasGetter()) {
1112
    return MakeMirror(this.getter_);
1113
  } else {
1114
    return new UndefinedMirror();
1115
  }
1116
}
1117

    
1118

    
1119
/**
1120
 * Returns the setter for this property defined through __defineSetter__.
1121
 * @return {Mirror} FunctionMirror reflecting the setter function or
1122
 *     UndefinedMirror if there is no setter for this property
1123
 */
1124
PropertyMirror.prototype.setter = function() {
1125
  if (this.hasSetter()) {
1126
    return MakeMirror(this.setter_);
1127
  } else {
1128
    return new UndefinedMirror();
1129
  }
1130
}
1131

    
1132

    
1133
/**
1134
 * Returns whether this property is natively implemented by the host or a set
1135
 * through JavaScript code.
1136
 * @return {boolean} True if the property is 
1137
 *     UndefinedMirror if there is no setter for this property
1138
 */
1139
PropertyMirror.prototype.isNative = function() {
1140
  return (this.propertyType() == PropertyType.Interceptor) ||
1141
         ((this.propertyType() == PropertyType.Callbacks) &&
1142
          !this.hasGetter() && !this.hasSetter());
1143
}
1144

    
1145

    
1146
const kFrameDetailsFrameIdIndex = 0;
1147
const kFrameDetailsReceiverIndex = 1;
1148
const kFrameDetailsFunctionIndex = 2;
1149
const kFrameDetailsArgumentCountIndex = 3;
1150
const kFrameDetailsLocalCountIndex = 4;
1151
const kFrameDetailsSourcePositionIndex = 5;
1152
const kFrameDetailsConstructCallIndex = 6;
1153
const kFrameDetailsDebuggerFrameIndex = 7;
1154
const kFrameDetailsFirstDynamicIndex = 8;
1155

    
1156
const kFrameDetailsNameIndex = 0;
1157
const kFrameDetailsValueIndex = 1;
1158
const kFrameDetailsNameValueSize = 2;
1159

    
1160
/**
1161
 * Wrapper for the frame details information retreived from the VM. The frame
1162
 * details from the VM is an array with the following content. See runtime.cc
1163
 * Runtime_GetFrameDetails.
1164
 *     0: Id
1165
 *     1: Receiver
1166
 *     2: Function
1167
 *     3: Argument count
1168
 *     4: Local count
1169
 *     5: Source position
1170
 *     6: Construct call
1171
 *     Arguments name, value
1172
 *     Locals name, value
1173
 * @param {number} break_id Current break id
1174
 * @param {number} index Frame number
1175
 * @constructor
1176
 */
1177
function FrameDetails(break_id, index) {
1178
  this.break_id_ = break_id;
1179
  this.details_ = %GetFrameDetails(break_id, index);
1180
}
1181

    
1182

    
1183
FrameDetails.prototype.frameId = function() {
1184
  %CheckExecutionState(this.break_id_);
1185
  return this.details_[kFrameDetailsFrameIdIndex];
1186
}
1187

    
1188

    
1189
FrameDetails.prototype.receiver = function() {
1190
  %CheckExecutionState(this.break_id_);
1191
  return this.details_[kFrameDetailsReceiverIndex];
1192
}
1193

    
1194

    
1195
FrameDetails.prototype.func = function() {
1196
  %CheckExecutionState(this.break_id_);
1197
  return this.details_[kFrameDetailsFunctionIndex];
1198
}
1199

    
1200

    
1201
FrameDetails.prototype.isConstructCall = function() {
1202
  %CheckExecutionState(this.break_id_);
1203
  return this.details_[kFrameDetailsConstructCallIndex];
1204
}
1205

    
1206

    
1207
FrameDetails.prototype.isDebuggerFrame = function() {
1208
  %CheckExecutionState(this.break_id_);
1209
  return this.details_[kFrameDetailsDebuggerFrameIndex];
1210
}
1211

    
1212

    
1213
FrameDetails.prototype.argumentCount = function() {
1214
  %CheckExecutionState(this.break_id_);
1215
  return this.details_[kFrameDetailsArgumentCountIndex];
1216
}
1217

    
1218

    
1219
FrameDetails.prototype.argumentName = function(index) {
1220
  %CheckExecutionState(this.break_id_);
1221
  if (index >= 0 && index < this.argumentCount()) {
1222
    return this.details_[kFrameDetailsFirstDynamicIndex +
1223
                         index * kFrameDetailsNameValueSize +
1224
                         kFrameDetailsNameIndex]
1225
  }
1226
}
1227

    
1228

    
1229
FrameDetails.prototype.argumentValue = function(index) {
1230
  %CheckExecutionState(this.break_id_);
1231
  if (index >= 0 && index < this.argumentCount()) {
1232
    return this.details_[kFrameDetailsFirstDynamicIndex +
1233
                         index * kFrameDetailsNameValueSize +
1234
                         kFrameDetailsValueIndex]
1235
  }
1236
}
1237

    
1238

    
1239
FrameDetails.prototype.localCount = function() {
1240
  %CheckExecutionState(this.break_id_);
1241
  return this.details_[kFrameDetailsLocalCountIndex];
1242
}
1243

    
1244

    
1245
FrameDetails.prototype.sourcePosition = function() {
1246
  %CheckExecutionState(this.break_id_);
1247
  return this.details_[kFrameDetailsSourcePositionIndex];
1248
}
1249

    
1250

    
1251
FrameDetails.prototype.localName = function(index) {
1252
  %CheckExecutionState(this.break_id_);
1253
  if (index >= 0 && index < this.localCount()) {
1254
    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1255
    return this.details_[locals_offset +
1256
                         index * kFrameDetailsNameValueSize +
1257
                         kFrameDetailsNameIndex]
1258
  }
1259
}
1260

    
1261

    
1262
FrameDetails.prototype.localValue = function(index) {
1263
  %CheckExecutionState(this.break_id_);
1264
  if (index >= 0 && index < this.localCount()) {
1265
    var locals_offset = kFrameDetailsFirstDynamicIndex + this.argumentCount() * kFrameDetailsNameValueSize
1266
    return this.details_[locals_offset +
1267
                         index * kFrameDetailsNameValueSize +
1268
                         kFrameDetailsValueIndex]
1269
  }
1270
}
1271

    
1272

    
1273
/**
1274
 * Mirror object for stack frames.
1275
 * @param {number} break_id The break id in the VM for which this frame is
1276
       valid
1277
 * @param {number} index The frame index (top frame is index 0)
1278
 * @constructor
1279
 * @extends Mirror
1280
 */
1281
function FrameMirror(break_id, index) {
1282
  Mirror.call(this, FRAME_TYPE);
1283
  this.break_id_ = break_id;
1284
  this.index_ = index;
1285
  this.details_ = new FrameDetails(break_id, index);
1286
}
1287
inherits(FrameMirror, Mirror);
1288

    
1289

    
1290
FrameMirror.prototype.index = function() {
1291
  return this.index_;
1292
};
1293

    
1294

    
1295
FrameMirror.prototype.func = function() {
1296
  // Get the function for this frame from the VM.
1297
  var f = this.details_.func();
1298
  
1299
  // Create a function mirror. NOTE: MakeMirror cannot be used here as the
1300
  // value returned from the VM might be a string if the function for the
1301
  // frame is unresolved.
1302
  if (IS_FUNCTION(f)) {
1303
    return MakeMirror(f);
1304
  } else {
1305
    return new UnresolvedFunctionMirror(f);
1306
  }
1307
};
1308

    
1309

    
1310
FrameMirror.prototype.receiver = function() {
1311
  return MakeMirror(this.details_.receiver());
1312
};
1313

    
1314

    
1315
FrameMirror.prototype.isConstructCall = function() {
1316
  return this.details_.isConstructCall();
1317
};
1318

    
1319

    
1320
FrameMirror.prototype.isDebuggerFrame = function() {
1321
  return this.details_.isDebuggerFrame();
1322
};
1323

    
1324

    
1325
FrameMirror.prototype.argumentCount = function() {
1326
  return this.details_.argumentCount();
1327
};
1328

    
1329

    
1330
FrameMirror.prototype.argumentName = function(index) {
1331
  return this.details_.argumentName(index);
1332
};
1333

    
1334

    
1335
FrameMirror.prototype.argumentValue = function(index) {
1336
  return MakeMirror(this.details_.argumentValue(index));
1337
};
1338

    
1339

    
1340
FrameMirror.prototype.localCount = function() {
1341
  return this.details_.localCount();
1342
};
1343

    
1344

    
1345
FrameMirror.prototype.localName = function(index) {
1346
  return this.details_.localName(index);
1347
};
1348

    
1349

    
1350
FrameMirror.prototype.localValue = function(index) {
1351
  return MakeMirror(this.details_.localValue(index));
1352
};
1353

    
1354

    
1355
FrameMirror.prototype.sourcePosition = function() {
1356
  return this.details_.sourcePosition();
1357
};
1358

    
1359

    
1360
FrameMirror.prototype.sourceLocation = function() {
1361
  if (this.func().resolved() && this.func().script()) {
1362
    return this.func().script().locationFromPosition(this.sourcePosition(),
1363
                                                     true);
1364
  }
1365
};
1366

    
1367

    
1368
FrameMirror.prototype.sourceLine = function() {
1369
  if (this.func().resolved()) {
1370
    var location = this.sourceLocation();
1371
    if (location) {
1372
      return location.line;
1373
    }
1374
  }
1375
};
1376

    
1377

    
1378
FrameMirror.prototype.sourceColumn = function() {
1379
  if (this.func().resolved()) {
1380
    var location = this.sourceLocation();
1381
    if (location) {
1382
      return location.column;
1383
    }
1384
  }
1385
};
1386

    
1387

    
1388
FrameMirror.prototype.sourceLineText = function() {
1389
  if (this.func().resolved()) {
1390
    var location = this.sourceLocation();
1391
    if (location) {
1392
      return location.sourceText();
1393
    }
1394
  }
1395
};
1396

    
1397

    
1398
FrameMirror.prototype.evaluate = function(source, disable_break) {
1399
  var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
1400
                              source, Boolean(disable_break));
1401
  return MakeMirror(result);
1402
};
1403

    
1404

    
1405
FrameMirror.prototype.invocationText = function() {
1406
  // Format frame invoaction (receiver, function and arguments).
1407
  var result = '';
1408
  var func = this.func();
1409
  var receiver = this.receiver();
1410
  if (this.isConstructCall()) {
1411
    // For constructor frames display new followed by the function name.
1412
    result += 'new ';
1413
    result += func.name() ? func.name() : '[anonymous]';
1414
  } else if (this.isDebuggerFrame()) {
1415
    result += '[debugger]';
1416
  } else {
1417
    // If the receiver has a className which is 'global' don't display it.
1418
    var display_receiver = !receiver.className || receiver.className() != 'global';
1419
    if (display_receiver) {
1420
      result += receiver.toText();
1421
    }
1422
    // Try to find the function as a property in the receiver. Include the
1423
    // prototype chain in the lookup.
1424
    var property = GetUndefinedMirror();
1425
    if (!receiver.isUndefined()) {
1426
      for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
1427
        property = r.lookupProperty(func);
1428
      }
1429
    }
1430
    if (!property.isUndefined()) {
1431
      // The function invoked was found on the receiver. Use the property name
1432
      // for the backtrace.
1433
      if (!property.isIndexed()) {
1434
        if (display_receiver) {
1435
          result += '.';
1436
        }
1437
        result += property.name();
1438
      } else {
1439
        result += '[';
1440
        result += property.name();
1441
        result += ']';
1442
      }
1443
      // Also known as - if the name in the function doesn't match the name
1444
      // under which it was looked up.
1445
      if (func.name() && func.name() != property.name()) {
1446
        result += '(aka ' + func.name() + ')';
1447
      }
1448
    } else {
1449
      // The function invoked was not found on the receiver. Use the function
1450
      // name if available for the backtrace.
1451
      if (display_receiver) {
1452
        result += '.';
1453
      }
1454
      result += func.name() ? func.name() : '[anonymous]';
1455
    }
1456
  }
1457

    
1458
  // Render arguments for normal frames.
1459
  if (!this.isDebuggerFrame()) {
1460
    result += '(';
1461
    for (var i = 0; i < this.argumentCount(); i++) {
1462
      if (i != 0) result += ', ';
1463
      if (this.argumentName(i)) {
1464
        result += this.argumentName(i);
1465
        result += '=';
1466
      }
1467
      result += this.argumentValue(i).toText();
1468
    }
1469
    result += ')';
1470
  }
1471

    
1472
  return result;
1473
}
1474

    
1475

    
1476
FrameMirror.prototype.sourceAndPositionText = function() {
1477
  // Format source and position.
1478
  var result = '';
1479
  var func = this.func();
1480
  if (func.resolved()) {
1481
    if (func.script()) {
1482
      if (func.script().name()) {
1483
        result += func.script().name();
1484
      } else {
1485
        result += '[unnamed]';
1486
      }
1487
      if (!this.isDebuggerFrame()) {
1488
        var location = this.sourceLocation();
1489
        result += ' line ';
1490
        result += !IS_UNDEFINED(location) ? (location.line + 1) : '?';
1491
        result += ' column ';
1492
        result += !IS_UNDEFINED(location) ? (location.column + 1) : '?';
1493
        if (!IS_UNDEFINED(this.sourcePosition())) {
1494
          result += ' (position ' + (this.sourcePosition() + 1) + ')';
1495
        }
1496
      }
1497
    } else {
1498
      result += '[no source]';
1499
    }
1500
  } else {
1501
    result += '[unresolved]';
1502
  }
1503

    
1504
  return result;
1505
}
1506

    
1507

    
1508
FrameMirror.prototype.localsText = function() {
1509
  // Format local variables.
1510
  var result = '';
1511
  var locals_count = this.localCount()
1512
  if (locals_count > 0) {
1513
    for (var i = 0; i < locals_count; ++i) {
1514
      result += '      var ';
1515
      result += this.localName(i);
1516
      result += ' = ';
1517
      result += this.localValue(i).toText();
1518
      if (i < locals_count - 1) result += '\n';
1519
    }
1520
  }
1521

    
1522
  return result;
1523
}
1524

    
1525

    
1526
FrameMirror.prototype.toText = function(opt_locals) {
1527
  var result = '';
1528
  result += '#' + (this.index() <= 9 ? '0' : '') + this.index();
1529
  result += ' ';
1530
  result += this.invocationText();
1531
  result += ' ';
1532
  result += this.sourceAndPositionText();
1533
  if (opt_locals) {
1534
    result += '\n';
1535
    result += this.localsText();
1536
  }
1537
  return result;
1538
}
1539

    
1540

    
1541
/**
1542
 * Mirror object for script source.
1543
 * @param {Script} script The script object
1544
 * @constructor
1545
 * @extends Mirror
1546
 */
1547
function ScriptMirror(script) {
1548
  Mirror.call(this, SCRIPT_TYPE);
1549
  this.script_ = script;
1550
  this.allocateHandle_();
1551
}
1552
inherits(ScriptMirror, Mirror);
1553

    
1554

    
1555
ScriptMirror.prototype.value = function() {
1556
  return this.script_;
1557
};
1558

    
1559

    
1560
ScriptMirror.prototype.name = function() {
1561
  return this.script_.name;
1562
};
1563

    
1564

    
1565
ScriptMirror.prototype.id = function() {
1566
  return this.script_.id;
1567
};
1568

    
1569

    
1570
ScriptMirror.prototype.source = function() {
1571
  return this.script_.source;
1572
};
1573

    
1574

    
1575
ScriptMirror.prototype.lineOffset = function() {
1576
  return this.script_.line_offset;
1577
};
1578

    
1579

    
1580
ScriptMirror.prototype.columnOffset = function() {
1581
  return this.script_.column_offset;
1582
};
1583

    
1584

    
1585
ScriptMirror.prototype.scriptType = function() {
1586
  return this.script_.type;
1587
};
1588

    
1589

    
1590
ScriptMirror.prototype.lineCount = function() {
1591
  return this.script_.lineCount();
1592
};
1593

    
1594

    
1595
ScriptMirror.prototype.locationFromPosition = function(
1596
    position, include_resource_offset) {
1597
  return this.script_.locationFromPosition(position, include_resource_offset);
1598
}
1599

    
1600

    
1601
ScriptMirror.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
1602
  return this.script_.sourceSlice(opt_from_line, opt_to_line);
1603
}
1604

    
1605

    
1606
ScriptMirror.prototype.toText = function() {
1607
  var result = '';
1608
  result += this.name();
1609
  result += ' (lines: ';
1610
  if (this.lineOffset() > 0) {
1611
    result += this.lineOffset();
1612
    result += '-';
1613
    result += this.lineOffset() + this.lineCount() - 1;
1614
  } else {
1615
    result += this.lineCount();
1616
  }
1617
  result += ')';
1618
  return result;
1619
}
1620

    
1621

    
1622
/**
1623
 * Returns a mirror serializer
1624
 *
1625
 * @param {boolean} details Set to true to include details
1626
 * @returns {MirrorSerializer} mirror serializer
1627
 */
1628
function MakeMirrorSerializer(details) {
1629
  return new JSONProtocolSerializer(details);
1630
}
1631

    
1632

    
1633
/**
1634
 * Object for serializing a mirror objects and its direct references.
1635
 * @param {boolean} details Indicates whether to include details for the mirror
1636
 *     serialized
1637
 * @constructor
1638
 */
1639
function JSONProtocolSerializer(details) {
1640
  this.details_ = details;
1641
  this.mirrors_ = [ ];
1642
}
1643

    
1644

    
1645
/**
1646
 * Returns a serialization of an object reference. The referenced object are
1647
 * added to the serialization state.
1648
 *
1649
 * @param {Mirror} mirror The mirror to serialize
1650
 * @returns {String} JSON serialization
1651
 */
1652
JSONProtocolSerializer.prototype.serializeReference = function(mirror) {
1653
  return this.serialize_(mirror, true, true);
1654
}
1655

    
1656

    
1657
/**
1658
 * Returns a serialization of an object value. The referenced objects are
1659
 * added to the serialization state.
1660
 *
1661
 * @param {Mirror} mirror The mirror to serialize
1662
 * @returns {String} JSON serialization
1663
 */
1664
JSONProtocolSerializer.prototype.serializeValue = function(mirror) {
1665
  var json = this.serialize_(mirror, false, true);
1666
  return json;
1667
}
1668

    
1669

    
1670
/**
1671
 * Returns a serialization of all the objects referenced.
1672
 *
1673
 * @param {Mirror} mirror The mirror to serialize
1674
 * @returns {String} JSON serialization
1675
 */
1676
JSONProtocolSerializer.prototype.serializeReferencedObjects = function() {
1677
  // Collect the JSON serialization of the referenced objects in an array.
1678
  var content = new Array();
1679
  
1680
  // Get the number of referenced objects.
1681
  var count = this.mirrors_.length;
1682
  
1683
  for (var i = 0; i < count; i++) {
1684
    content.push(this.serialize_(this.mirrors_[i], false, false));
1685
  }
1686

    
1687
  var json = ArrayToJSONArray_(content);
1688
  return json;
1689
}
1690

    
1691

    
1692
JSONProtocolSerializer.prototype.add_ = function(mirror) {
1693
  // If this mirror is already in the list just return.
1694
  for (var i = 0; i < this.mirrors_.length; i++) {
1695
    if (this.mirrors_[i] === mirror) {
1696
      return;
1697
    }
1698
  }
1699
  
1700
  // Add the mirror to the list of mirrors to be serialized.
1701
  this.mirrors_.push(mirror);
1702
}
1703

    
1704

    
1705
JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
1706
                                                       details) {
1707
  // If serializing a reference to a mirror just return the reference and add
1708
  // the mirror to the referenced mirrors.
1709
  if (reference &&
1710
      (mirror.isValue() || mirror.isScript())) {
1711
    this.add_(mirror);
1712
    return '{"ref":' + mirror.handle() + '}';
1713
  }
1714
  
1715
  // Collect the JSON property/value pairs in an array.
1716
  var content = new Array();
1717

    
1718
  // Add the mirror handle.
1719
  if (mirror.isValue() || mirror.isScript()) {
1720
    content.push(MakeJSONPair_('handle', NumberToJSON_(mirror.handle())));
1721
  }
1722

    
1723
  // Always add the type.
1724
  content.push(MakeJSONPair_('type', StringToJSON_(mirror.type())));
1725

    
1726
  switch (mirror.type()) {
1727
    case UNDEFINED_TYPE:
1728
    case NULL_TYPE:
1729
      // Undefined and null are represented just by their type.
1730
      break;
1731

    
1732
    case BOOLEAN_TYPE:
1733
      // Boolean values are simply represented by their value.
1734
      content.push(MakeJSONPair_('value', BooleanToJSON_(mirror.value())));
1735
      break;
1736

    
1737
    case NUMBER_TYPE:
1738
      // Number values are simply represented by their value.
1739
      content.push(MakeJSONPair_('value', NumberToJSON_(mirror.value())));
1740
      break;
1741

    
1742
    case STRING_TYPE:
1743
      // String values might have their value cropped to keep down size.
1744
      if (mirror.length() > kMaxProtocolStringLength) {
1745
        var str = mirror.value().substring(0, kMaxProtocolStringLength);
1746
        content.push(MakeJSONPair_('value', StringToJSON_(str)));
1747
        content.push(MakeJSONPair_('fromIndex', NumberToJSON_(0)));
1748
        content.push(MakeJSONPair_('toIndex',
1749
                                   NumberToJSON_(kMaxProtocolStringLength)));
1750
      } else {
1751
        content.push(MakeJSONPair_('value', StringToJSON_(mirror.value())));
1752
      }
1753
      content.push(MakeJSONPair_('length', NumberToJSON_(mirror.length())));
1754
      break;
1755

    
1756
    case OBJECT_TYPE:
1757
    case FUNCTION_TYPE:
1758
    case ERROR_TYPE:
1759
    case REGEXP_TYPE:
1760
      // Add object representation.
1761
      this.serializeObject_(mirror, content, details);
1762
      break;
1763

    
1764
    case PROPERTY_TYPE:
1765
      throw new Error('PropertyMirror cannot be serialized independeltly')
1766
      break;
1767

    
1768
    case FRAME_TYPE:
1769
      // Add object representation.
1770
      this.serializeFrame_(mirror, content);
1771
      break;
1772

    
1773
    case SCRIPT_TYPE:
1774
      // Script is represented by id, name and source attributes.
1775
      if (mirror.name()) {
1776
        content.push(MakeJSONPair_('name', StringToJSON_(mirror.name())));
1777
      }
1778
      content.push(MakeJSONPair_('id', NumberToJSON_(mirror.id())));
1779
      content.push(MakeJSONPair_('lineOffset',
1780
                                 NumberToJSON_(mirror.lineOffset())));
1781
      content.push(MakeJSONPair_('columnOffset',
1782
                                 NumberToJSON_(mirror.columnOffset())));
1783
      content.push(MakeJSONPair_('lineCount',
1784
                                 NumberToJSON_(mirror.lineCount())));
1785
      content.push(MakeJSONPair_('scriptType',
1786
                                 NumberToJSON_(mirror.scriptType())));
1787
      break;
1788
  }
1789

    
1790
  // Always add the text representation.
1791
  content.push(MakeJSONPair_('text', StringToJSON_(mirror.toText())));
1792
  
1793
  // Create and return the JSON string.
1794
  return ArrayToJSONObject_(content);
1795
}
1796

    
1797

    
1798
/**
1799
 * Serialize object information to the following JSON format.
1800
 *
1801
 *   {"className":"<class name>",
1802
 *    "constructorFunction":{"ref":<number>},
1803
 *    "protoObject":{"ref":<number>},
1804
 *    "prototypeObject":{"ref":<number>},
1805
 *    "namedInterceptor":<boolean>,
1806
 *    "indexedInterceptor":<boolean>,
1807
 *    "properties":[<properties>]}
1808
 */
1809
JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
1810
                                                             details) {
1811
  // Add general object properties.
1812
  content.push(MakeJSONPair_('className',
1813
                             StringToJSON_(mirror.className())));
1814
  content.push(MakeJSONPair_('constructorFunction',
1815
      this.serializeReference(mirror.constructorFunction())));
1816
  content.push(MakeJSONPair_('protoObject',
1817
      this.serializeReference(mirror.protoObject())));
1818
  content.push(MakeJSONPair_('prototypeObject',
1819
      this.serializeReference(mirror.prototypeObject())));
1820

    
1821
  // Add flags to indicate whether there are interceptors.
1822
  if (mirror.hasNamedInterceptor()) {
1823
    content.push(MakeJSONPair_('namedInterceptor', BooleanToJSON_(true)));
1824
  }
1825
  if (mirror.hasIndexedInterceptor()) {
1826
    content.push(MakeJSONPair_('indexedInterceptor', BooleanToJSON_(true)));
1827
  }
1828
  
1829
  // Add function specific properties.
1830
  if (mirror.isFunction()) {
1831
    // Add function specific properties.
1832
    content.push(MakeJSONPair_('name', StringToJSON_(mirror.name())));
1833
    content.push(MakeJSONPair_('resolved', BooleanToJSON_(mirror.resolved())));
1834
    if (mirror.resolved()) {
1835
      content.push(MakeJSONPair_('source', StringToJSON_(mirror.source())));
1836
    }
1837
    if (mirror.script()) {
1838
      content.push(MakeJSONPair_('script', this.serializeReference(mirror.script())));
1839
    }
1840
  }
1841

    
1842
  // Add date specific properties.
1843
  if (mirror.isDate()) {
1844
    // Add date specific properties.
1845
    content.push(MakeJSONPair_('value', DateToJSON_(mirror.value())));
1846
  }
1847

    
1848
  // Add actual properties - named properties followed by indexed properties.
1849
  var propertyNames = mirror.propertyNames(PropertyKind.Named);
1850
  var propertyIndexes = mirror.propertyNames(PropertyKind.Indexed);
1851
  var p = new Array(propertyNames.length + propertyIndexes.length);
1852
  for (var i = 0; i < propertyNames.length; i++) {
1853
    var property_mirror = mirror.property(propertyNames[i]);
1854
    p[i] = this.serializeProperty_(property_mirror);
1855
    if (details) {
1856
      this.add_(property_mirror.value());
1857
    }
1858
  }
1859
  for (var i = 0; i < propertyIndexes.length; i++) {
1860
    var property_mirror = mirror.property(propertyIndexes[i]);
1861
    p[propertyNames.length + i] = this.serializeProperty_(property_mirror);
1862
    if (details) {
1863
      this.add_(property_mirror.value());
1864
    }
1865
  }
1866
  content.push(MakeJSONPair_('properties', ArrayToJSONArray_(p)));
1867
}
1868

    
1869

    
1870
/**
1871
 * Serialize property information to the following JSON format for building the
1872
 * array of properties.
1873
 *
1874
 *   {"name":"<property name>",
1875
 *    "attributes":<number>,
1876
 *    "propertyType":<number>,
1877
 *    "ref":<number>}
1878
 *
1879
 * If the attribute for the property is PropertyAttribute.None it is not added.
1880
 * If the propertyType for the property is PropertyType.Normal it is not added.
1881
 * Here are a couple of examples.
1882
 *
1883
 *   {"name":"hello","ref":1}
1884
 *   {"name":"length","attributes":7,"propertyType":3,"ref":2}
1885
 *
1886
 * @param {PropertyMirror} property_mirror The property to serialize
1887
 * @returns {String} JSON serialization
1888
 */
1889
JSONProtocolSerializer.prototype.serializeProperty_ = function(property_mirror) {
1890
  var builder = new builtins.StringBuilder();
1891
  builder.add('{"name":');
1892
  builder.add(StringToJSON_(property_mirror.name()));
1893
  if (property_mirror.attributes() != PropertyAttribute.None) {
1894
    builder.add(',"attributes":');
1895
    builder.add(NumberToJSON_(property_mirror.attributes()));
1896
  }
1897
  if (property_mirror.propertyType() != PropertyType.Normal) {
1898
    builder.add(',"propertyType":');
1899
    builder.add(NumberToJSON_(property_mirror.propertyType()));
1900
  }
1901
  builder.add(',"ref":');
1902
  builder.add(NumberToJSON_(property_mirror.value().handle()));
1903
  builder.add('}');
1904
  return builder.generate();
1905
}
1906

    
1907

    
1908
JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
1909
  content.push(MakeJSONPair_('index', NumberToJSON_(mirror.index())));
1910
  content.push(MakeJSONPair_('receiver',
1911
                             this.serializeReference(mirror.receiver())));
1912
  var func = mirror.func();
1913
  content.push(MakeJSONPair_('func', this.serializeReference(func)));
1914
  if (func.script()) {
1915
    content.push(MakeJSONPair_('script',
1916
                               this.serializeReference(func.script())));
1917
  }
1918
  content.push(MakeJSONPair_('constructCall',
1919
                             BooleanToJSON_(mirror.isConstructCall())));
1920
  content.push(MakeJSONPair_('debuggerFrame',
1921
                             BooleanToJSON_(mirror.isDebuggerFrame())));
1922
  var x = new Array(mirror.argumentCount());
1923
  for (var i = 0; i < mirror.argumentCount(); i++) {
1924
    arg = new Array();
1925
    var argument_name = mirror.argumentName(i)
1926
    if (argument_name) {
1927
      arg.push(MakeJSONPair_('name', StringToJSON_(argument_name)));
1928
    }
1929
    arg.push(MakeJSONPair_('value',
1930
                           this.serializeReference(mirror.argumentValue(i))));
1931
    x[i] = ArrayToJSONObject_(arg);
1932
  }
1933
  content.push(MakeJSONPair_('arguments', ArrayToJSONArray_(x)));
1934
  var x = new Array(mirror.localCount());
1935
  for (var i = 0; i < mirror.localCount(); i++) {
1936
    var name = MakeJSONPair_('name', StringToJSON_(mirror.localName(i)));
1937
    var value = MakeJSONPair_('value',
1938
                              this.serializeReference(mirror.localValue(i)));
1939
    x[i] = '{' + name + ',' + value + '}';
1940
  }
1941
  content.push(MakeJSONPair_('locals', ArrayToJSONArray_(x)));
1942
  content.push(MakeJSONPair_('position',
1943
                             NumberToJSON_(mirror.sourcePosition())));
1944
  var line = mirror.sourceLine();
1945
  if (!IS_UNDEFINED(line)) {
1946
    content.push(MakeJSONPair_('line', NumberToJSON_(line)));
1947
  }
1948
  var column = mirror.sourceColumn();
1949
  if (!IS_UNDEFINED(column)) {
1950
    content.push(MakeJSONPair_('column', NumberToJSON_(column)));
1951
  }
1952
  var source_line_text = mirror.sourceLineText();
1953
  if (!IS_UNDEFINED(source_line_text)) {
1954
    content.push(MakeJSONPair_('sourceLineText',
1955
                               StringToJSON_(source_line_text)));
1956
  }
1957
}
1958

    
1959

    
1960
function MakeJSONPair_(name, value) {
1961
  return '"' + name + '":' + value;
1962
}
1963

    
1964

    
1965
function ArrayToJSONObject_(content) {
1966
  return '{' + content.join(',') + '}';
1967
}
1968

    
1969

    
1970
function ArrayToJSONArray_(content) {
1971
  return '[' + content.join(',') + ']';
1972
}
1973

    
1974

    
1975
function BooleanToJSON_(value) {
1976
  return String(value); 
1977
}
1978

    
1979

    
1980
/**
1981
 * Convert a number to a JSON string value. For all finite numbers the number
1982
 * literal representation is used. For non finite numbers NaN, Infinite and
1983
 * -Infinite the string representation "NaN", "Infinite" or "-Infinite"
1984
 * (including the quotes) is returned.
1985
 *
1986
 * @param {number} value The number value to convert to a JSON value
1987
 * @returns {String} JSON value
1988
 */
1989
function NumberToJSON_(value) {
1990
  if (isNaN(value)) {
1991
    return '"NaN"';
1992
  }
1993
  if (!isFinite(value)) {
1994
    if (value > 0) {
1995
      return '"Infinity"';
1996
    } else {
1997
      return '"-Infinity"';
1998
    }
1999
  }
2000
  return String(value); 
2001
}
2002

    
2003

    
2004
// Mapping of some control characters to avoid the \uXXXX syntax for most
2005
// commonly used control cahracters.
2006
const ctrlCharMap_ = {
2007
  '\b': '\\b',
2008
  '\t': '\\t',
2009
  '\n': '\\n',
2010
  '\f': '\\f',
2011
  '\r': '\\r',
2012
  '"' : '\\"',
2013
  '\\': '\\\\'
2014
};
2015

    
2016

    
2017
// Regular expression testing for ", \ and control characters (0x00 - 0x1F).
2018
const ctrlCharTest_ = new RegExp('["\\\\\x00-\x1F]');
2019

    
2020

    
2021
// Regular expression matching ", \ and control characters (0x00 - 0x1F)
2022
// globally.
2023
const ctrlCharMatch_ = new RegExp('["\\\\\x00-\x1F]', 'g');
2024

    
2025

    
2026
/**
2027
 * Convert a String to its JSON representation (see http://www.json.org/). To
2028
 * avoid depending on the String object this method calls the functions in
2029
 * string.js directly and not through the value.
2030
 * @param {String} value The String value to format as JSON
2031
 * @return {string} JSON formatted String value
2032
 */
2033
function StringToJSON_(value) {
2034
  // Check for" , \ and control characters (0x00 - 0x1F). No need to call
2035
  // RegExpTest as ctrlchar is constructed using RegExp.
2036
  if (ctrlCharTest_.test(value)) {
2037
    // Replace ", \ and control characters (0x00 - 0x1F).
2038
    return '"' +
2039
      value.replace(ctrlCharMatch_, function (char) {
2040
        // Use charmap if possible.
2041
        var mapped = ctrlCharMap_[char];
2042
        if (mapped) return mapped;
2043
        mapped = char.charCodeAt();
2044
        // Convert control character to unicode escape sequence.
2045
        return '\\u00' +
2046
          %NumberToRadixString(Math.floor(mapped / 16), 16) +
2047
          %NumberToRadixString(mapped % 16, 16);
2048
      })
2049
    + '"';
2050
  }
2051

    
2052
  // Simple string with no special characters.
2053
  return '"' + value + '"';
2054
}
2055

    
2056

    
2057
/**
2058
 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
2059
 * this method calls the functions in date.js directly and not through the
2060
 * value.
2061
 * @param {Date} value The Date value to format as JSON
2062
 * @return {string} JSON formatted Date value
2063
 */
2064
function DateToISO8601_(value) {
2065
  function f(n) {
2066
    return n < 10 ? '0' + n : n;
2067
  }
2068
  function g(n) {
2069
    return n < 10 ? '00' + n : n < 100 ? '0' + n : n;
2070
  }
2071
  return builtins.GetUTCFullYearFrom(value)         + '-' +
2072
          f(builtins.GetUTCMonthFrom(value) + 1)    + '-' +
2073
          f(builtins.GetUTCDateFrom(value))         + 'T' +
2074
          f(builtins.GetUTCHoursFrom(value))        + ':' +
2075
          f(builtins.GetUTCMinutesFrom(value))      + ':' +
2076
          f(builtins.GetUTCSecondsFrom(value))      + '.' +
2077
          g(builtins.GetUTCMillisecondsFrom(value)) + 'Z';
2078
}
2079

    
2080
/**
2081
 * Convert a Date to ISO 8601 format. To avoid depending on the Date object
2082
 * this method calls the functions in date.js directly and not through the
2083
 * value.
2084
 * @param {Date} value The Date value to format as JSON
2085
 * @return {string} JSON formatted Date value
2086
 */
2087
function DateToJSON_(value) {
2088
  return '"' + DateToISO8601_(value) + '"';
2089
}