Index: src/mirror-delay.js |
=================================================================== |
--- src/mirror-delay.js (revision 2147) |
+++ src/mirror-delay.js (working copy) |
@@ -34,9 +34,14 @@ |
Date; |
+// Handle id counters. |
var next_handle_ = 0; |
+var next_transient_handle_ = -1; |
+ |
+// Mirror cache. |
var mirror_cache_ = []; |
+ |
/** |
* Clear the mirror handle cache. |
*/ |
@@ -50,20 +55,26 @@ |
* Returns the mirror for a specified value or object. |
* |
* @param {value or Object} value the value or object to retreive the mirror for |
+ * @param {boolean} transient indicate whether this object is transient and |
+ * should not be added to the mirror cache. The default is not transient. |
* @returns {Mirror} the mirror reflects the passed value or object |
*/ |
-function MakeMirror(value) { |
+function MakeMirror(value, opt_transient) { |
var mirror; |
- for (id in mirror_cache_) { |
- mirror = mirror_cache_[id]; |
- if (mirror.value() === value) { |
- return mirror; |
+ |
+ // Look for non transient mirrors in the mirror cache. |
+ if (!opt_transient) { |
+ for (id in mirror_cache_) { |
+ mirror = mirror_cache_[id]; |
+ if (mirror.value() === value) { |
+ return mirror; |
+ } |
+ // Special check for NaN as NaN == NaN is false. |
+ if (mirror.isNumber() && isNaN(mirror.value()) && |
+ typeof value == 'number' && isNaN(value)) { |
+ return mirror; |
+ } |
} |
- // Special check for NaN as NaN == NaN is false. |
- if (mirror.isNumber() && isNaN(mirror.value()) && |
- typeof value == 'number' && isNaN(value)) { |
- return mirror; |
- } |
} |
if (IS_UNDEFINED(value)) { |
@@ -89,7 +100,7 @@ |
} else if (IS_SCRIPT(value)) { |
mirror = new ScriptMirror(value); |
} else { |
- mirror = new ObjectMirror(value); |
+ mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient); |
} |
mirror_cache_[mirror.handle()] = mirror; |
@@ -155,6 +166,7 @@ |
const FRAME_TYPE = 'frame'; |
const SCRIPT_TYPE = 'script'; |
const CONTEXT_TYPE = 'context'; |
+const SCOPE_TYPE = 'scope'; |
// Maximum length when sending strings through the JSON protocol. |
const kMaxProtocolStringLength = 80; |
@@ -185,6 +197,13 @@ |
PropertyAttribute.DontDelete = DONT_DELETE; |
+// A copy of the scope types from runtime.cc. |
+ScopeType = { Global: 0, |
+ Local: 1, |
+ With: 2, |
+ Closure: 3 }; |
+ |
+ |
// Mirror hierarchy: |
// - Mirror |
// - ValueMirror |
@@ -373,6 +392,15 @@ |
/** |
+ * Check whether the mirror reflects a scope. |
+ * @returns {boolean} True if the mirror reflects a scope |
+ */ |
+Mirror.prototype.isScope = function() { |
+ return this instanceof ScopeMirror; |
+} |
+ |
+ |
+/** |
* Allocate a handle id for this object. |
*/ |
Mirror.prototype.allocateHandle_ = function() { |
@@ -380,6 +408,15 @@ |
} |
+/** |
+ * Allocate a transient handle id for this object. Transient handles are |
+ * negative. |
+ */ |
+Mirror.prototype.allocateTransientHandle_ = function() { |
+ this.handle_ = next_transient_handle_--; |
+} |
+ |
+ |
Mirror.prototype.toText = function() { |
// Simpel to text which is used when on specialization in subclass. |
return "#<" + builtins.GetInstanceName(this.constructor.name) + ">"; |
@@ -390,13 +427,19 @@ |
* Base class for all value mirror objects. |
* @param {string} type The type of the mirror |
* @param {value} value The value reflected by this mirror |
+ * @param {boolean} transient indicate whether this object is transient with a |
+ * transient handle |
* @constructor |
* @extends Mirror |
*/ |
-function ValueMirror(type, value) { |
+function ValueMirror(type, value, transient) { |
Mirror.call(this, type); |
this.value_ = value; |
- this.allocateHandle_(); |
+ if (!transient) { |
+ this.allocateHandle_(); |
+ } else { |
+ this.allocateTransientHandle_(); |
+ } |
} |
inherits(ValueMirror, Mirror); |
@@ -525,11 +568,13 @@ |
/** |
* Mirror object for objects. |
* @param {object} value The object reflected by this mirror |
+ * @param {boolean} transient indicate whether this object is transient with a |
+ * transient handle |
* @constructor |
* @extends ValueMirror |
*/ |
-function ObjectMirror(value, type) { |
- ValueMirror.call(this, type || OBJECT_TYPE, value); |
+function ObjectMirror(value, type, transient) { |
+ ValueMirror.call(this, type || OBJECT_TYPE, value, transient); |
} |
inherits(ObjectMirror, ValueMirror); |
@@ -1080,7 +1125,7 @@ |
PropertyMirror.prototype.value = function() { |
- return MakeMirror(this.value_); |
+ return MakeMirror(this.value_, false); |
} |
@@ -1135,7 +1180,7 @@ |
if (this.hasGetter()) { |
return MakeMirror(this.getter_); |
} else { |
- return new UndefinedMirror(); |
+ return GetUndefinedMirror(); |
} |
} |
@@ -1149,7 +1194,7 @@ |
if (this.hasSetter()) { |
return MakeMirror(this.setter_); |
} else { |
- return new UndefinedMirror(); |
+ return GetUndefinedMirror(); |
} |
} |
@@ -1294,6 +1339,11 @@ |
} |
+FrameDetails.prototype.scopeCount = function() { |
+ return %GetScopeCount(this.break_id_, this.frameId()); |
+} |
+ |
+ |
/** |
* Mirror object for stack frames. |
* @param {number} break_id The break id in the VM for which this frame is |
@@ -1419,6 +1469,16 @@ |
}; |
+FrameMirror.prototype.scopeCount = function() { |
+ return this.details_.scopeCount(); |
+}; |
+ |
+ |
+FrameMirror.prototype.scope = function(index) { |
+ return new ScopeMirror(this, index); |
+}; |
+ |
+ |
FrameMirror.prototype.evaluate = function(source, disable_break) { |
var result = %DebugEvaluate(this.break_id_, this.details_.frameId(), |
source, Boolean(disable_break)); |
@@ -1562,7 +1622,71 @@ |
} |
+const kScopeDetailsTypeIndex = 0; |
+const kScopeDetailsObjectIndex = 1; |
+ |
+function ScopeDetails(frame, index) { |
+ this.break_id_ = frame.break_id_; |
+ this.details_ = %GetScopeDetails(frame.break_id_, |
+ frame.details_.frameId(), |
+ index); |
+} |
+ |
+ |
+ScopeDetails.prototype.type = function() { |
+ %CheckExecutionState(this.break_id_); |
+ return this.details_[kScopeDetailsTypeIndex]; |
+} |
+ |
+ |
+ScopeDetails.prototype.object = function() { |
+ %CheckExecutionState(this.break_id_); |
+ return this.details_[kScopeDetailsObjectIndex]; |
+} |
+ |
+ |
/** |
+ * Mirror object for scope. |
+ * @param {FrameMirror} frame The frame this scope is a part of |
+ * @param {number} index The scope index in the frame |
+ * @constructor |
+ * @extends Mirror |
+ */ |
+function ScopeMirror(frame, index) { |
+ Mirror.call(this, SCOPE_TYPE); |
+ this.frame_index_ = frame.index_; |
+ this.scope_index_ = index; |
+ this.details_ = new ScopeDetails(frame, index); |
+} |
+inherits(ScopeMirror, Mirror); |
+ |
+ |
+ScopeMirror.prototype.frameIndex = function() { |
+ return this.frame_index_; |
+}; |
+ |
+ |
+ScopeMirror.prototype.scopeIndex = function() { |
+ return this.scope_index_; |
+}; |
+ |
+ |
+ScopeMirror.prototype.scopeType = function() { |
+ return this.details_.type(); |
+}; |
+ |
+ |
+ScopeMirror.prototype.scopeObject = function() { |
+ // For local and closure scopes create a transient mirror as these objects are |
+ // created on the fly materializing the local or closure scopes and |
+ // therefore will not preserve identity. |
+ var transient = this.scopeType() == ScopeType.Local || |
+ this.scopeType() == ScopeType.Closure; |
+ return MakeMirror(this.details_.object(), transient); |
+}; |
+ |
+ |
+/** |
* Mirror object for script source. |
* @param {Script} script The script object |
* @constructor |
@@ -1829,6 +1953,7 @@ |
return o; |
}; |
+ |
JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, |
details) { |
// If serializing a reference to a mirror just return the reference and add |
@@ -1900,6 +2025,11 @@ |
this.serializeFrame_(mirror, content); |
break; |
+ case SCOPE_TYPE: |
+ // Add object representation. |
+ this.serializeScope_(mirror, content); |
+ break; |
+ |
case SCRIPT_TYPE: |
// Script is represented by id, name and source attributes. |
if (mirror.name()) { |
@@ -2102,6 +2232,14 @@ |
} |
+JSONProtocolSerializer.prototype.serializeScope_ = function(mirror, content) { |
+ content.index = mirror.scopeIndex(); |
+ content.frameIndex = mirror.frameIndex(); |
+ content.type = mirror.scopeType(); |
+ content.object = this.serializeReference(mirror.scopeObject()); |
+} |
+ |
+ |
/** |
* Convert a number to a protocol value. For all finite numbers the number |
* itself is returned. For non finite numbers NaN, Infinite and |