diff options
-rw-r--r-- | webkit/glue/devtools/js/debugger_agent.js | 194 | ||||
-rw-r--r-- | webkit/glue/devtools/js/devtools.js | 85 | ||||
-rw-r--r-- | webkit/glue/devtools/js/dom_agent.js | 4 |
3 files changed, 231 insertions, 52 deletions
diff --git a/webkit/glue/devtools/js/debugger_agent.js b/webkit/glue/devtools/js/debugger_agent.js index 6dcb83d..647a84b 100644 --- a/webkit/glue/devtools/js/debugger_agent.js +++ b/webkit/glue/devtools/js/debugger_agent.js @@ -20,16 +20,16 @@ devtools.DebuggerAgent = function() { * Mapping from script id to script info. * @type {Object} */ - this.parsedScripts_ = {}; + this.parsedScripts_ = null; /** * Mapping from the request id to the devtools.BreakpointInfo for the * breakpoints whose v8 ids are not set yet. These breakpoints are waiting for * 'setbreakpoint' responses to learn their ids in the v8 debugger. * @see #handleSetBreakpointResponse_ - * @type {!Object} + * @type {Object} */ - this.requestNumberToBreakpointInfo_ = {}; + this.requestNumberToBreakpointInfo_ = null; /** * Information on current stack top frame. @@ -41,6 +41,16 @@ devtools.DebuggerAgent = function() { /** + * Resets debugger agent to its initial state. + */ + devtools.DebuggerAgent.prototype.reset = function() { + this.parsedScripts_ = {}; + this.requestNumberToBreakpointInfo_ = {}; + this.currentCallFrame_ = null; + }; + + +/** * Asynchronously requests for all parsed script sources. Response will be * processed in handleScriptsResponse_. */ @@ -50,7 +60,7 @@ devtools.DebuggerAgent.prototype.requestScripts = function() { }); devtools.DebuggerAgent.sendCommand_(cmd); // Force v8 execution so that it gets to processing the requested command. - devtools.tools.evaluateJavaScript("javascript:void(0)");
+ devtools.tools.evaluateJavaScript('javascript:void(0)');
}; @@ -223,8 +233,8 @@ devtools.DebuggerAgent.prototype.handleDebuggerOutput_ = function(output) { if (msg.getType() == 'event') { if (msg.getEvent() == 'break') { this.handleBreakEvent_(msg); - } else if (msg.getEvent() == 'exception') { - this.handleExceptionEvent_(msg); + } else if (msg.getEvent() == 'exception') {
+ this.handleExceptionEvent_(msg);
} } else if (msg.getType() == 'response') { if (msg.getCommand() == 'scripts') { @@ -261,11 +271,11 @@ devtools.DebuggerAgent.prototype.handleBreakEvent_ = function(msg) { /** * @param {devtools.DebuggerMessage} msg */ -devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) { - var body = msg.getBody(); - debugPrint('Uncaught exception in ' + body.script.name + ':' + - body.sourceLine + '\n' + body.sourceLineText); - this.resumeExecution(); +devtools.DebuggerAgent.prototype.handleExceptionEvent_ = function(msg) {
+ var body = msg.getBody();
+ debugPrint('Uncaught exception in ' + body.script.name + ':' +
+ body.sourceLine + '\n' + body.sourceLineText);
+ this.resumeExecution();
}; @@ -340,42 +350,14 @@ devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { var script = this.currentCallFrame_.script; - var caller = null; + var callerFrame = null; var f = null; var frames = msg.getBody().frames; for (var i = frames.length - 1; i>=0; i--) { var nextFrame = frames[i]; - var func = msg.lookup(nextFrame.func.ref); - - // Format arguments. - var argv = []; - for (var j = 0; j < nextFrame.arguments.length; j++) { - var arg = nextFrame.arguments[j]; - var val = msg.lookup(arg.value.ref); - if (val) { - if (val.value) { - argv.push(arg.name + " = " + val.value); - } else { - argv.push(arg.name + " = [" + val.type + "]"); - } - - } else { - argv.push(arg.name + " = {ref:" + arg.value.ref + "} "); - } - } - - var funcName = func.name + "(" + argv.join(", ") + ")"; - - var f = { - 'sourceID': script.id, - 'line': nextFrame.line - script.lineOffset +1, - 'type': 'function', - 'functionName': funcName, //nextFrame.text, - 'caller': caller, - 'scopeChain': [], - 'thisObject': {} - }; - caller = f; + var f = devtools.DebuggerAgent.formatCallFrame_(nextFrame, script, msg); + f.caller = callerFrame; + callerFrame = f; } this.currentCallFrame_ = f; @@ -385,6 +367,132 @@ devtools.DebuggerAgent.prototype.handleBacktraceResponse_ = function(msg) { /** + * @param {Object} stackFrame Frame json object from 'backtrace' response. + * @param {Object} script Script json object from 'break' event. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + * @return {!Object} Object containing information related to the call frame in + * the format expected by ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.formatCallFrame_ = function(stackFrame, script, msg) { + var funcName = devtools.DebuggerAgent.formatFunction_(stackFrame, msg); + + var scope = {}; + + // Add arguments. + devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.arguments, scope, msg); + + // Add local variables. + devtools.DebuggerAgent.valuesArrayToMap_(stackFrame.locals, scope, msg); + + var thisObject = msg.lookup(stackFrame.receiver.ref); + // Add variable with name 'this' to the scope. + scope['this'] = devtools.DebuggerAgent.formatObject_(thisObject, msg); + + return { + 'sourceID': script.id, + 'line': stackFrame.line - script.lineOffset +1, + 'type': 'function', + 'functionName': funcName, //stackFrame.text, + 'caller': null, + 'localScope': scope, + 'scopeChain': [scope], + 'thisObject': thisObject, + }; +}; + + +/** + * Returns user-friendly representation of the function call from the stack + * frame. + * @param {Object} stackFrame Frame json object from 'backtrace' response. + * @return {!string} Function name with argument values. + */ +devtools.DebuggerAgent.formatFunction_ = function(stackFrame, msg) { + var func = msg.lookup(stackFrame.func.ref); + var argv = []; + for (var j = 0; j < stackFrame.arguments.length; j++) { + var arg = stackFrame.arguments[j]; + var val = devtools.DebuggerAgent.formatObjectReference_(arg.value, msg); + argv.push(arg.name + ' = ' + val); + } + return func.name + '(' + argv.join(', ') + ')'; +}; + + +/** + * @param {Object} thisObject Receiver json object from 'backtrace' response. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + * @return {!Object} Object describing 'this' in the format expected by + * ScriptsPanel and its panes. + */ +devtools.DebuggerAgent.formatObject_ = function(thisObject, msg) { + var result = {}; + devtools.DebuggerAgent.propertiesToMap_(thisObject.properties, result, msg); + result.protoObject = devtools.DebuggerAgent.formatObjectReference_( + thisObject.protoObject, msg); + result.prototypeObject = devtools.DebuggerAgent.formatObjectReference_( + thisObject.prototypeObject, msg); + return result; +}; + + +/** + * For each property in 'properties' puts its name and user-friendly value into + * 'map'. + * @param {Array.<Object>} properties Receiver properties array from 'backtrace' + * response. + * @param {Object} map Result holder. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + */ +devtools.DebuggerAgent.propertiesToMap_ = function(properties, map, msg) { + for (var j = 0; j < properties.length; j++) { + var nextValue = properties[j]; + map[nextValue.name] =devtools.DebuggerAgent.formatObjectReference_( + nextValue, msg); + } +}; + + +/** + * For each property in 'array' puts its name and user-friendly value into + * 'map'. + * @param {Array.<Object>} array Arguments or locals array from 'backtrace' + * response. + * @param {Object} map Result holder. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + */ +devtools.DebuggerAgent.valuesArrayToMap_ = function(array, map, msg) { + for (var j = 0; j < array.length; j++) { + var nextValue = array[j]; + map[nextValue.name] = devtools.DebuggerAgent.formatObjectReference_( + nextValue.value, msg); + } +}; + + +/** + * @param {Object} objectRef Object reference from the debugger protocol. + * @param {devtools.DebuggerMessage} msg Parsed 'backtrace' response. + * @return {string} User-friendly representation of the reference. + */ +devtools.DebuggerAgent.formatObjectReference_ = function(objectRef, msg) { + if (!objectRef.ref) { + return 'illegal ref'; + } + + var object = msg.lookup(objectRef.ref); + if (!object) { + return '{ref: ' + objectRef.ref + '}'; + } + + if ('value' in object) { + return object.value; + } + return '[' + object.type + ']'; +}; + + +/** * @param {number} scriptId Id of the script. * @param {number} lineOffset First line 0-based offset in the containing * document. diff --git a/webkit/glue/devtools/js/devtools.js b/webkit/glue/devtools/js/devtools.js index 1cc682d..b3b6266 100644 --- a/webkit/glue/devtools/js/devtools.js +++ b/webkit/glue/devtools/js/devtools.js @@ -24,17 +24,19 @@ devtools.ToolsAgent = function() { this.debuggerAgent_ = new devtools.DebuggerAgent(); this.domAgent_ = new devtools.DomAgent(); this.netAgent_ = new devtools.NetAgent(); - this.reset(); }; /** - * Rests tools agent to its initial state. + * Resets tools agent to its initial state. */ devtools.ToolsAgent.prototype.reset = function() { this.domAgent_.reset(); this.netAgent_.reset(); + this.debuggerAgent_.reset(); + this.domAgent_.getDocumentElementAsync(); + this.debuggerAgent_.requestScripts(); }; @@ -168,12 +170,12 @@ var context = {}; // Used by WebCore's inspector routines. var oldLoaded = WebInspector.loaded; WebInspector.loaded = function() { devtools.tools = new devtools.ToolsAgent(); + devtools.tools.reset(); Preferences.ignoreWhitespace = false; oldLoaded.call(this); DevToolsHost.loaded(); - devtools.tools.getDebuggerAgent().requestScripts(); }; @@ -285,12 +287,13 @@ WebInspector.PropertiesSidebarPane.prototype.update = function(object) { var self = this; devtools.tools.getNodePrototypesAsync(object.id_, function(json) { + // Get array of prototype user-friendly names. var prototypes = goog.json.parse(json); for (var i = 0; i < prototypes.length; ++i) { var prototype = {}; prototype.id_ = object.id_; prototype.protoDepth_ = i; - var section = new WebInspector.ObjectPropertiesSection(prototype, + var section = new WebInspector.SidebarObjectPropertiesSection(prototype, prototypes[i]); self.sections.push(section); body.appendChild(section.element); @@ -300,9 +303,24 @@ WebInspector.PropertiesSidebarPane.prototype.update = function(object) { /** + * Our implementation of ObjectPropertiesSection for Elements tab. + * @constructor + */ +WebInspector.SidebarObjectPropertiesSection = function(object, title) { + WebInspector.ObjectPropertiesSection.call(this, object, title, + null /* subtitle */, null /* emptyPlaceholder */, + null /* ignoreHasOwnProperty */, null /* extraProperties */, + WebInspector.SidebarObjectPropertyTreeElement /* treeElementConstructor */ + ); +}; +goog.inherits(WebInspector.SidebarObjectPropertiesSection, + WebInspector.ObjectPropertiesSection); + + +/** * @override */ -WebInspector.ObjectPropertiesSection.prototype.onpopulate = function() { +WebInspector.SidebarObjectPropertiesSection.prototype.onpopulate = function() { var nodeId = this.object.id_; var protoDepth = this.object.protoDepth_; var path = []; @@ -316,9 +334,22 @@ WebInspector.ObjectPropertiesSection.prototype.onpopulate = function() { /** + * Our implementation of ObjectPropertyTreeElement for Elements tab. + * @constructor + */ +WebInspector.SidebarObjectPropertyTreeElement = function(parentObject, + propertyName) { + WebInspector.ObjectPropertyTreeElement.call(this, parentObject, propertyName); +}; +goog.inherits(WebInspector.SidebarObjectPropertyTreeElement, + WebInspector.ObjectPropertyTreeElement); + + +/** * @override */ -WebInspector.ObjectPropertyTreeElement.prototype.onpopulate = function() { +WebInspector.SidebarObjectPropertyTreeElement.prototype.onpopulate = + function() { var nodeId = this.parentObject.devtools$$nodeId_; var path = this.parentObject.devtools$$path_.slice(0); path.push(this.propertyName); @@ -413,3 +444,45 @@ WebInspector.didGetNodePropertiesAsync_ = function(treeOutline, constructor, treeOutline.appendChild(new constructor(obj, propertyName)); } }; + + +/** + * Replace WebKit method with our own implementation to use our call stack + * representation. Original method uses Object.prototype.toString.call to + * learn if scope object is a JSActivation which doesn't work in Chrome. + */ +WebInspector.ScopeChainSidebarPane.prototype.update = function(callFrame) {
+ this.bodyElement.removeChildren();
+
+ this.sections = [];
+ this.callFrame = callFrame;
+
+ if (!callFrame) {
+ var infoElement = document.createElement("div");
+ infoElement.className = "info";
+ infoElement.textContent = WebInspector.UIString("Not Paused");
+ this.bodyElement.appendChild(infoElement);
+ return;
+ }
+
+ if (!callFrame._expandedProperties) {
+ callFrame._expandedProperties = {};
+ }
+
+ var scopeObject = callFrame.localScope;
+ var title = WebInspector.UIString("Local");
+ var subtitle = Object.describe(scopeObject, true);
+ var emptyPlaceholder = null;
+ var extraProperties = null;
+
+ var section = new WebInspector.ObjectPropertiesSection(scopeObject, title,
+ subtitle, emptyPlaceholder, true, extraProperties,
+ WebInspector.ScopeVariableTreeElement);
+ section.editInSelectedCallFrameWhenPaused = true;
+ section.pane = this;
+
+ section.expanded = true;
+
+ this.sections.push(section);
+ this.bodyElement.appendChild(section.element);
+};
diff --git a/webkit/glue/devtools/js/dom_agent.js b/webkit/glue/devtools/js/dom_agent.js index 12330b2..31d13a7 100644 --- a/webkit/glue/devtools/js/dom_agent.js +++ b/webkit/glue/devtools/js/dom_agent.js @@ -540,13 +540,11 @@ devtools.DomAgent = function() { * @private */ this.searchResults_ = null; - - this.reset(); }; /** - * Rests dom agent to its initial state. + * Resets dom agent to its initial state. */ devtools.DomAgent.prototype.reset = function() { this.window_ = new devtools.DomWindow(this); |