Commit 88261439 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Add scope chain information to the debugger.

For each frame it is now possible to request information on the scope chain. Each scope in the chain can have one of the types local, global, with and closure. For scopes of type global and with the mirror for the actual global or with object is available. For scopes of type local and closure a plain JavaScript object with the materialized content of the scope is created and its mirror is returned. Depending on the level of possible optimization the content of the materialized local and closure scopes might only contain the names which are actually used.

To iterate the scope chain an iterator ScopeIterator have been added which can provide the type of each scope for each part of the chain. This iterator creates an artificial local scope whenever that is present as the context chain does not include the local scope.

To avoid caching the mirror objects for the materialized the local and closure scopes transient mirrors have been added. They have negative handles and cannot be retrieved by subsequent lookup calls. Their content is part of a single response.

For debugging purposes an additional runtime function DebugPrintScopes is been added.

Added commands 'scopes' and 'scope' to the developer shell and fixed the dir command.

BUG=none
TEST=test/mjsunit/debug-scopes.js
Review URL: http://codereview.chromium.org/123021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2149 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d62f77fd
...@@ -98,6 +98,13 @@ Debug.ScriptCompilationType = { Host: 0, ...@@ -98,6 +98,13 @@ Debug.ScriptCompilationType = { Host: 0,
JSON: 2 }; JSON: 2 };
// The different types of scopes matching constants runtime.cc.
Debug.ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3 };
// Current debug state. // Current debug state.
const kNoFrame = -1; const kNoFrame = -1;
Debug.State = { Debug.State = {
...@@ -295,6 +302,14 @@ function DebugRequest(cmd_line) { ...@@ -295,6 +302,14 @@ function DebugRequest(cmd_line) {
this.request_ = this.frameCommandToJSONRequest_(args); this.request_ = this.frameCommandToJSONRequest_(args);
break; break;
case 'scopes':
this.request_ = this.scopesCommandToJSONRequest_(args);
break;
case 'scope':
this.request_ = this.scopeCommandToJSONRequest_(args);
break;
case 'print': case 'print':
case 'p': case 'p':
this.request_ = this.printCommandToJSONRequest_(args); this.request_ = this.printCommandToJSONRequest_(args);
...@@ -394,13 +409,17 @@ DebugRequest.prototype.createRequest = function(command) { ...@@ -394,13 +409,17 @@ DebugRequest.prototype.createRequest = function(command) {
// Create a JSON request for the evaluation command. // Create a JSON request for the evaluation command.
DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) { DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) {
// Global varaible used to store whether a handle was requested.
lookup_handle = null;
// Check if the expression is a handle id in the form #<handle>#. // Check if the expression is a handle id in the form #<handle>#.
var handle_match = expression.match(/^#([0-9]*)#$/); var handle_match = expression.match(/^#([0-9]*)#$/);
if (handle_match) { if (handle_match) {
// Remember the handle requested in a global variable.
lookup_handle = parseInt(handle_match[1]);
// Build a lookup request. // Build a lookup request.
var request = this.createRequest('lookup'); var request = this.createRequest('lookup');
request.arguments = {}; request.arguments = {};
request.arguments.handle = parseInt(handle_match[1]); request.arguments.handles = [ lookup_handle ];
return request.toJSONProtocol(); return request.toJSONProtocol();
} else { } else {
// Build an evaluate request. // Build an evaluate request.
...@@ -559,6 +578,27 @@ DebugRequest.prototype.frameCommandToJSONRequest_ = function(args) { ...@@ -559,6 +578,27 @@ DebugRequest.prototype.frameCommandToJSONRequest_ = function(args) {
}; };
// Create a JSON request for the scopes command.
DebugRequest.prototype.scopesCommandToJSONRequest_ = function(args) {
// Build a scopes request from the text command.
var request = this.createRequest('scopes');
return request.toJSONProtocol();
};
// Create a JSON request for the scope command.
DebugRequest.prototype.scopeCommandToJSONRequest_ = function(args) {
// Build a scope request from the text command.
var request = this.createRequest('scope');
args = args.split(/\s*[ ]+\s*/g);
if (args.length > 0 && args[0].length > 0) {
request.arguments = {};
request.arguments.number = args[0];
}
return request.toJSONProtocol();
};
// Create a JSON request for the print command. // Create a JSON request for the print command.
DebugRequest.prototype.printCommandToJSONRequest_ = function(args) { DebugRequest.prototype.printCommandToJSONRequest_ = function(args) {
// Build an evaluate request from the text command. // Build an evaluate request from the text command.
...@@ -783,8 +823,11 @@ DebugRequest.prototype.helpCommand_ = function(args) { ...@@ -783,8 +823,11 @@ DebugRequest.prototype.helpCommand_ = function(args) {
print('clear <breakpoint #>'); print('clear <breakpoint #>');
print('backtrace [n] | [-n] | [from to]'); print('backtrace [n] | [-n] | [from to]');
print('frame <frame #>'); print('frame <frame #>');
print('scopes');
print('scope <scope #>');
print('step [in | next | out| min [step count]]'); print('step [in | next | out| min [step count]]');
print('print <expression>'); print('print <expression>');
print('dir <expression>');
print('source [from line [num lines]]'); print('source [from line [num lines]]');
print('scripts'); print('scripts');
print('continue'); print('continue');
...@@ -794,7 +837,11 @@ DebugRequest.prototype.helpCommand_ = function(args) { ...@@ -794,7 +837,11 @@ DebugRequest.prototype.helpCommand_ = function(args) {
function formatHandleReference_(value) { function formatHandleReference_(value) {
return '#' + value.handle() + '#'; if (value.handle() >= 0) {
return '#' + value.handle() + '#';
} else {
return '#Transient#';
}
} }
...@@ -818,10 +865,14 @@ function formatObject_(value, include_properties) { ...@@ -818,10 +865,14 @@ function formatObject_(value, include_properties) {
result += value.propertyName(i); result += value.propertyName(i);
result += ': '; result += ': ';
var property_value = value.propertyValue(i); var property_value = value.propertyValue(i);
if (property_value && property_value.type()) { if (property_value instanceof ProtocolReference) {
result += property_value.type();
} else {
result += '<no type>'; result += '<no type>';
} else {
if (property_value && property_value.type()) {
result += property_value.type();
} else {
result += '<no type>';
}
} }
result += ' '; result += ' ';
result += formatHandleReference_(property_value); result += formatHandleReference_(property_value);
...@@ -832,6 +883,33 @@ function formatObject_(value, include_properties) { ...@@ -832,6 +883,33 @@ function formatObject_(value, include_properties) {
} }
function formatScope_(scope) {
var result = '';
var index = scope.index;
result += '#' + (index <= 9 ? '0' : '') + index;
result += ' ';
switch (scope.type) {
case Debug.ScopeType.Global:
result += 'Global, ';
result += '#' + scope.object.ref + '#';
break;
case Debug.ScopeType.Local:
result += 'Local';
break;
case Debug.ScopeType.With:
result += 'With, ';
result += '#' + scope.object.ref + '#';
break;
case Debug.ScopeType.Closure:
result += 'Closure';
break;
default:
result += 'UNKNOWN';
}
return result;
}
// Convert a JSON response to text for display in a text based debugger. // Convert a JSON response to text for display in a text based debugger.
function DebugResponseDetails(response) { function DebugResponseDetails(response) {
details = {text:'', running:false} details = {text:'', running:false}
...@@ -881,12 +959,41 @@ function DebugResponseDetails(response) { ...@@ -881,12 +959,41 @@ function DebugResponseDetails(response) {
Debug.State.currentFrame = body.index; Debug.State.currentFrame = body.index;
break; break;
case 'scopes':
if (body.totalScopes == 0) {
result = '(no scopes)';
} else {
result = 'Scopes #' + body.fromScope + ' to #' +
(body.toScope - 1) + ' of ' + body.totalScopes + '\n';
for (i = 0; i < body.scopes.length; i++) {
if (i != 0) {
result += '\n';
}
result += formatScope_(body.scopes[i]);
}
}
details.text = result;
break;
case 'scope':
result += formatScope_(body);
result += '\n';
var scope_object_value = response.lookup(body.object.ref);
result += formatObject_(scope_object_value, true);
details.text = result;
break;
case 'evaluate': case 'evaluate':
case 'lookup': case 'lookup':
if (last_cmd == 'p' || last_cmd == 'print') { if (last_cmd == 'p' || last_cmd == 'print') {
result = body.text; result = body.text;
} else { } else {
var value = response.bodyValue(); var value;
if (lookup_handle) {
value = response.bodyValue(lookup_handle);
} else {
value = response.bodyValue();
}
if (value.isObject()) { if (value.isObject()) {
result += formatObject_(value, true); result += formatObject_(value, true);
} else { } else {
...@@ -1103,7 +1210,7 @@ ProtocolPackage.prototype.body = function() { ...@@ -1103,7 +1210,7 @@ ProtocolPackage.prototype.body = function() {
ProtocolPackage.prototype.bodyValue = function(index) { ProtocolPackage.prototype.bodyValue = function(index) {
if (index) { if (index != null) {
return new ProtocolValue(this.packet_.body[index], this); return new ProtocolValue(this.packet_.body[index], this);
} else { } else {
return new ProtocolValue(this.packet_.body, this); return new ProtocolValue(this.packet_.body, this);
......
...@@ -1208,6 +1208,10 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) ...@@ -1208,6 +1208,10 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
this.backtraceRequest_(request, response); this.backtraceRequest_(request, response);
} else if (request.command == 'frame') { } else if (request.command == 'frame') {
this.frameRequest_(request, response); this.frameRequest_(request, response);
} else if (request.command == 'scopes') {
this.scopesRequest_(request, response);
} else if (request.command == 'scope') {
this.scopeRequest_(request, response);
} else if (request.command == 'evaluate') { } else if (request.command == 'evaluate') {
this.evaluateRequest_(request, response); this.evaluateRequest_(request, response);
} else if (request.command == 'lookup') { } else if (request.command == 'lookup') {
...@@ -1540,7 +1544,7 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) { ...@@ -1540,7 +1544,7 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
// With no arguments just keep the selected frame. // With no arguments just keep the selected frame.
if (request.arguments) { if (request.arguments) {
index = request.arguments.number; var index = request.arguments.number;
if (index < 0 || this.exec_state_.frameCount() <= index) { if (index < 0 || this.exec_state_.frameCount() <= index) {
return response.failed('Invalid frame number'); return response.failed('Invalid frame number');
} }
...@@ -1551,6 +1555,67 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) { ...@@ -1551,6 +1555,67 @@ DebugCommandProcessor.prototype.frameRequest_ = function(request, response) {
}; };
DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
// Get the frame for which the scope or scopes are requested. With no frameNumber
// argument use the currently selected frame.
if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
frame_index = request.arguments.frameNumber;
if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
return response.failed('Invalid frame number');
}
return this.exec_state_.frame(frame_index);
} else {
return this.exec_state_.frame();
}
}
DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
// No frames no scopes.
if (this.exec_state_.frameCount() == 0) {
return response.failed('No scopes');
}
// Get the frame for which the scopes are requested.
var frame = this.frameForScopeRequest_(request);
// Fill all scopes for this frame.
var total_scopes = frame.scopeCount();
var scopes = [];
for (var i = 0; i < total_scopes; i++) {
scopes.push(frame.scope(i));
}
response.body = {
fromScope: 0,
toScope: total_scopes,
totalScopes: total_scopes,
scopes: scopes
}
};
DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
// No frames no scopes.
if (this.exec_state_.frameCount() == 0) {
return response.failed('No scopes');
}
// Get the frame for which the scope is requested.
var frame = this.frameForScopeRequest_(request);
// With no scope argument just return top scope.
var scope_index = 0;
if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
scope_index = %ToNumber(request.arguments.number);
if (scope_index < 0 || frame.scopeCount() <= scope_index) {
return response.failed('Invalid scope number');
}
}
response.body = frame.scope(scope_index);
};
DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) { DebugCommandProcessor.prototype.evaluateRequest_ = function(request, response) {
if (!request.arguments) { if (!request.arguments) {
return response.failed('Missing arguments'); return response.failed('Missing arguments');
......
...@@ -34,9 +34,14 @@ RegExp; ...@@ -34,9 +34,14 @@ RegExp;
Date; Date;
// Handle id counters.
var next_handle_ = 0; var next_handle_ = 0;
var next_transient_handle_ = -1;
// Mirror cache.
var mirror_cache_ = []; var mirror_cache_ = [];
/** /**
* Clear the mirror handle cache. * Clear the mirror handle cache.
*/ */
...@@ -50,19 +55,25 @@ function ClearMirrorCache() { ...@@ -50,19 +55,25 @@ function ClearMirrorCache() {
* Returns the mirror for a specified value or object. * Returns the mirror for a specified value or object.
* *
* @param {value or Object} value the value or object to retreive the mirror for * @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 * @returns {Mirror} the mirror reflects the passed value or object
*/ */
function MakeMirror(value) { function MakeMirror(value, opt_transient) {
var mirror; var mirror;
for (id in mirror_cache_) {
mirror = mirror_cache_[id]; // Look for non transient mirrors in the mirror cache.
if (mirror.value() === value) { if (!opt_transient) {
return mirror; for (id in mirror_cache_) {
} mirror = mirror_cache_[id];
// Special check for NaN as NaN == NaN is false. if (mirror.value() === value) {
if (mirror.isNumber() && isNaN(mirror.value()) && return mirror;
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;
}
} }
} }
...@@ -89,7 +100,7 @@ function MakeMirror(value) { ...@@ -89,7 +100,7 @@ function MakeMirror(value) {
} else if (IS_SCRIPT(value)) { } else if (IS_SCRIPT(value)) {
mirror = new ScriptMirror(value); mirror = new ScriptMirror(value);
} else { } else {
mirror = new ObjectMirror(value); mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient);
} }
mirror_cache_[mirror.handle()] = mirror; mirror_cache_[mirror.handle()] = mirror;
...@@ -155,6 +166,7 @@ const PROPERTY_TYPE = 'property'; ...@@ -155,6 +166,7 @@ const PROPERTY_TYPE = 'property';
const FRAME_TYPE = 'frame'; const FRAME_TYPE = 'frame';
const SCRIPT_TYPE = 'script'; const SCRIPT_TYPE = 'script';
const CONTEXT_TYPE = 'context'; const CONTEXT_TYPE = 'context';
const SCOPE_TYPE = 'scope';
// Maximum length when sending strings through the JSON protocol. // Maximum length when sending strings through the JSON protocol.
const kMaxProtocolStringLength = 80; const kMaxProtocolStringLength = 80;
...@@ -185,6 +197,13 @@ PropertyAttribute.DontEnum = DONT_ENUM; ...@@ -185,6 +197,13 @@ PropertyAttribute.DontEnum = DONT_ENUM;
PropertyAttribute.DontDelete = DONT_DELETE; 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 hierarchy:
// - Mirror // - Mirror
// - ValueMirror // - ValueMirror
...@@ -372,6 +391,15 @@ Mirror.prototype.isContext = function() { ...@@ -372,6 +391,15 @@ Mirror.prototype.isContext = function() {
} }
/**
* 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. * Allocate a handle id for this object.
*/ */
...@@ -380,6 +408,15 @@ Mirror.prototype.allocateHandle_ = function() { ...@@ -380,6 +408,15 @@ Mirror.prototype.allocateHandle_ = function() {
} }
/**
* 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() { Mirror.prototype.toText = function() {
// Simpel to text which is used when on specialization in subclass. // Simpel to text which is used when on specialization in subclass.
return "#<" + builtins.GetInstanceName(this.constructor.name) + ">"; return "#<" + builtins.GetInstanceName(this.constructor.name) + ">";
...@@ -390,13 +427,19 @@ Mirror.prototype.toText = function() { ...@@ -390,13 +427,19 @@ Mirror.prototype.toText = function() {
* Base class for all value mirror objects. * Base class for all value mirror objects.
* @param {string} type The type of the mirror * @param {string} type The type of the mirror
* @param {value} value The value reflected by this mirror * @param {value} value The value reflected by this mirror
* @param {boolean} transient indicate whether this object is transient with a
* transient handle
* @constructor * @constructor
* @extends Mirror * @extends Mirror
*/ */
function ValueMirror(type, value) { function ValueMirror(type, value, transient) {
Mirror.call(this, type); Mirror.call(this, type);
this.value_ = value; this.value_ = value;
this.allocateHandle_(); if (!transient) {
this.allocateHandle_();
} else {
this.allocateTransientHandle_();
}
} }
inherits(ValueMirror, Mirror); inherits(ValueMirror, Mirror);
...@@ -525,11 +568,13 @@ StringMirror.prototype.toText = function() { ...@@ -525,11 +568,13 @@ StringMirror.prototype.toText = function() {
/** /**
* Mirror object for objects. * Mirror object for objects.
* @param {object} value The object reflected by this mirror * @param {object} value The object reflected by this mirror
* @param {boolean} transient indicate whether this object is transient with a
* transient handle
* @constructor * @constructor
* @extends ValueMirror * @extends ValueMirror
*/ */
function ObjectMirror(value, type) { function ObjectMirror(value, type, transient) {
ValueMirror.call(this, type || OBJECT_TYPE, value); ValueMirror.call(this, type || OBJECT_TYPE, value, transient);
} }
inherits(ObjectMirror, ValueMirror); inherits(ObjectMirror, ValueMirror);
...@@ -1080,7 +1125,7 @@ PropertyMirror.prototype.isIndexed = function() { ...@@ -1080,7 +1125,7 @@ PropertyMirror.prototype.isIndexed = function() {
PropertyMirror.prototype.value = function() { PropertyMirror.prototype.value = function() {
return MakeMirror(this.value_); return MakeMirror(this.value_, false);
} }
...@@ -1135,7 +1180,7 @@ PropertyMirror.prototype.getter = function() { ...@@ -1135,7 +1180,7 @@ PropertyMirror.prototype.getter = function() {
if (this.hasGetter()) { if (this.hasGetter()) {
return MakeMirror(this.getter_); return MakeMirror(this.getter_);
} else { } else {
return new UndefinedMirror(); return GetUndefinedMirror();
} }
} }
...@@ -1149,7 +1194,7 @@ PropertyMirror.prototype.setter = function() { ...@@ -1149,7 +1194,7 @@ PropertyMirror.prototype.setter = function() {
if (this.hasSetter()) { if (this.hasSetter()) {
return MakeMirror(this.setter_); return MakeMirror(this.setter_);
} else { } else {
return new UndefinedMirror(); return GetUndefinedMirror();
} }
} }
...@@ -1294,6 +1339,11 @@ FrameDetails.prototype.localValue = function(index) { ...@@ -1294,6 +1339,11 @@ FrameDetails.prototype.localValue = function(index) {
} }
FrameDetails.prototype.scopeCount = function() {
return %GetScopeCount(this.break_id_, this.frameId());
}
/** /**
* Mirror object for stack frames. * Mirror object for stack frames.
* @param {number} break_id The break id in the VM for which this frame is * @param {number} break_id The break id in the VM for which this frame is
...@@ -1419,6 +1469,16 @@ FrameMirror.prototype.sourceLineText = function() { ...@@ -1419,6 +1469,16 @@ FrameMirror.prototype.sourceLineText = function() {
}; };
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) { FrameMirror.prototype.evaluate = function(source, disable_break) {
var result = %DebugEvaluate(this.break_id_, this.details_.frameId(), var result = %DebugEvaluate(this.break_id_, this.details_.frameId(),
source, Boolean(disable_break)); source, Boolean(disable_break));
...@@ -1562,6 +1622,70 @@ FrameMirror.prototype.toText = function(opt_locals) { ...@@ -1562,6 +1622,70 @@ FrameMirror.prototype.toText = function(opt_locals) {
} }
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. * Mirror object for script source.
* @param {Script} script The script object * @param {Script} script The script object
...@@ -1829,6 +1953,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ = ...@@ -1829,6 +1953,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
return o; return o;
}; };
JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
details) { details) {
// If serializing a reference to a mirror just return the reference and add // If serializing a reference to a mirror just return the reference and add
...@@ -1900,6 +2025,11 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference, ...@@ -1900,6 +2025,11 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
this.serializeFrame_(mirror, content); this.serializeFrame_(mirror, content);
break; break;
case SCOPE_TYPE:
// Add object representation.
this.serializeScope_(mirror, content);
break;
case SCRIPT_TYPE: case SCRIPT_TYPE:
// Script is represented by id, name and source attributes. // Script is represented by id, name and source attributes.
if (mirror.name()) { if (mirror.name()) {
...@@ -2102,6 +2232,14 @@ JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) { ...@@ -2102,6 +2232,14 @@ JSONProtocolSerializer.prototype.serializeFrame_ = function(mirror, content) {
} }
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 * Convert a number to a protocol value. For all finite numbers the number
* itself is returned. For non finite numbers NaN, Infinite and * itself is returned. For non finite numbers NaN, Infinite and
......
This diff is collapsed.
...@@ -288,6 +288,9 @@ namespace internal { ...@@ -288,6 +288,9 @@ namespace internal {
F(CheckExecutionState, 1) \ F(CheckExecutionState, 1) \
F(GetFrameCount, 1) \ F(GetFrameCount, 1) \
F(GetFrameDetails, 2) \ F(GetFrameDetails, 2) \
F(GetScopeCount, 2) \
F(GetScopeDetails, 3) \
F(DebugPrintScopes, 0) \
F(GetCFrames, 1) \ F(GetCFrames, 1) \
F(GetThreadCount, 1) \ F(GetThreadCount, 1) \
F(GetThreadDetails, 2) \ F(GetThreadDetails, 2) \
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment