From 20a9e9b013d2e52cc581dc3ffb9deed2ff54955b Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Thu, 26 Feb 2009 11:55:35 +0000 Subject: [PATCH] Change the D8 JavaScript debugger to fully use the JSON protocol. The D8 debugger frontend now only processes JSON messages. Before the debugger events was passed as objects. Changed the debugger events JSON generation to use the same serailizer as the responses to requests. This provides correct serialization of mirror objects in debugger events. Renamed ResponsePacket to ProtocolMessage as it is not only used for responses. Review URL: http://codereview.chromium.org/27202 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1374 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/d8-debug.cc | 13 +++++- src/d8.cc | 2 +- src/d8.h | 2 +- src/d8.js | 110 +++++++++++++++++++++++---------------------- src/debug-delay.js | 92 +++++++++++++++++++++++++------------ 5 files changed, 135 insertions(+), 84 deletions(-) diff --git a/src/d8-debug.cc b/src/d8-debug.cc index 0e30a86d47..cfe69ca25d 100644 --- a/src/d8-debug.cc +++ b/src/d8-debug.cc @@ -46,8 +46,19 @@ void HandleDebugEvent(DebugEvent event, TryCatch try_catch; + // Get the toJSONProtocol function on the event and get the JSON format. + Local to_json_fun_name = String::New("toJSONProtocol"); + Local to_json_fun = + Function::Cast(*event_data->Get(to_json_fun_name)); + Local event_json = to_json_fun->Call(event_data, 0, NULL); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + return; + } + // Print the event details. - Handle details = Shell::DebugEventToText(event_data); + Handle details = + Shell::DebugEventToText(Handle::Cast(event_json)); if (details->Length() == 0) { // Empty string is used to signal not to process this event. return; diff --git a/src/d8.cc b/src/d8.cc index 8e415ca421..a049430183 100644 --- a/src/d8.cc +++ b/src/d8.cc @@ -232,7 +232,7 @@ Handle Shell::GetCompletions(Handle text, Handle full) { } -Handle Shell::DebugEventToText(Handle event) { +Handle Shell::DebugEventToText(Handle event) { HandleScope handle_scope; Context::Scope context_scope(utility_context_); Handle global = utility_context_->Global(); diff --git a/src/d8.h b/src/d8.h index 4614378aed..726b369bc9 100644 --- a/src/d8.h +++ b/src/d8.h @@ -88,7 +88,7 @@ class Shell: public i::AllStatic { static int Main(int argc, char* argv[]); static Handle GetCompletions(Handle text, Handle full); - static Handle DebugEventToText(Handle event); + static Handle DebugEventToText(Handle event); static Handle DebugCommandToJSONRequest(Handle command); static Handle DebugResponseDetails(Handle response); diff --git a/src/d8.js b/src/d8.js index b298a5ffc7..25896ba418 100644 --- a/src/d8.js +++ b/src/d8.js @@ -103,66 +103,54 @@ var trace_compile = false; // Tracing all compile events? function DebugEventToText(event) { - switch (event.eventType()) { - case Debug.DebugEvent.Break: - // Build the break details. - var details = ''; - if (event.breakPointsHit()) { + // Convert the JSON string to an object. + var response = new ProtocolPackage(event); + + // Build the text. + var body = response.body(); + var details = ''; + switch (response.event()) { + case 'break': + if (body.breakpoints) { details += 'breakpoint'; - if (event.breakPointsHit().length > 1) { + if (body.breakpoints.length > 1) { details += 's'; } details += ' #'; - for (var i = 0; i < event.breakPointsHit().length; i++) { + for (var i = 0; i < body.breakpoints.length; i++) { if (i > 0) { details += ', #'; } - // Find the break point number. For break points originating from a - // script break point display the script break point number. - var break_point = event.breakPointsHit()[i]; - var script_break_point = break_point.script_break_point(); - if (script_break_point) { - details += script_break_point.number(); - } else { - details += break_point.number(); - } + details += body.breakpoints[i]; } } else { details += 'break'; } details += ' in '; - details += event.executionState().frame(0).invocationText(); - details += ' at '; - details += event.executionState().frame(0).sourceAndPositionText(); - details += '\n' - if (event.func().script()) { - details += FrameSourceUnderline(event.executionState().frame(0)); - } - Debug.State.currentSourceLine = - event.executionState().frame(0).sourceLine(); + details += body.invocationText; + details += ', '; + details += SourceInfo(body); + details += '\n'; + details += SourceUnderline(body.sourceLineText, body.sourceColumn); + Debug.State.currentSourceLine = body.sourceLine; Debug.State.currentFrame = 0; return details; - - case Debug.DebugEvent.Exception: - var details = ''; - if (event.uncaught_) { + + case 'exception': + if (body.uncaught) { details += 'Uncaught: '; } else { details += 'Exception: '; } - details += '"'; - details += event.exception(); + details += body.exception.text; details += '"'; - if (event.executionState().frameCount() > 0) { - details += '"'; - details += event.exception(); - details += ' at '; - details += event.executionState().frame(0).sourceAndPositionText(); + if (body.sourceLine >= 0) { + details += ', '; + details += SourceInfo(body); details += '\n'; - details += FrameSourceUnderline(event.executionState().frame(0)); - Debug.State.currentSourceLine = - event.executionState().frame(0).sourceLine(); + details += SourceUnderline(body.sourceLineText, body.sourceColumn); + Debug.State.currentSourceLine = body.sourceLine; Debug.State.currentFrame = 0; } else { details += ' (empty stack)'; @@ -170,11 +158,18 @@ function DebugEventToText(event) { Debug.State.currentFrame = kNoFrame; } return details; - - case Debug.DebugEvent.AfterCompile: + + case 'exception': + if (trace_compile) { + details = 'Source ' + body.script.name + ' compiled:\n' + } else { + return ''; + } + + case 'afterCompile': if (trace_compile) { details = 'Source ' + event.script().name() + ' compiled:\n' - var source = event.script().source(); + var source = body.script.source; if (!(source[source.length - 1] == '\n')) { details += source; } else { @@ -185,11 +180,29 @@ function DebugEventToText(event) { return ''; } } - - return 'Unknown debug event ' + event.eventType(); + return 'Unknown debug event ' + response.event(); }; +function SourceInfo(body) { + var result = ''; + + if (body.script) { + if (body.script.name) { + result += body.script.name; + } else { + result += '[unnamed]'; + } + } + result += ' line '; + result += body.sourceLine + 1; + result += ' column '; + result += body.sourceColumn + 1; + + return result; +} + + function SourceUnderline(source_text, position) { if (!source_text) { return; @@ -213,15 +226,6 @@ function SourceUnderline(source_text, position) { }; -function FrameSourceUnderline(frame) { - var location = frame.sourceLocation(); - if (location) { - return SourceUnderline(location.sourceText(), - location.position - location.start); - } -}; - - // Converts a text command to a JSON request. function DebugCommandToJSONRequest(cmd_line) { return new DebugRequest(cmd_line).JSONRequest(); diff --git a/src/debug-delay.js b/src/debug-delay.js index 45e3c6e07d..cfd1c7d3a6 100644 --- a/src/debug-delay.js +++ b/src/debug-delay.js @@ -871,28 +871,32 @@ ExceptionEvent.prototype.sourceLineText = function() { ExceptionEvent.prototype.toJSONProtocol = function() { - var o = { seq: next_response_seq++, - type: "event", - event: "exception", - body: { uncaught: this.uncaught_, - exception: MakeMirror(this.exception_), - sourceLine: this.sourceLine(), - sourceColumn: this.sourceColumn(), - sourceLineText: this.sourceLineText(), - } - } + var o = new ProtocolMessage(); + o.event = "exception"; + o.body = { uncaught: this.uncaught_, + exception: MakeMirror(this.exception_) + } + + // Exceptions might happen whithout any JavaScript frames. + if (this.exec_state_.frameCount() > 0) { + o.body.sourceLine = this.sourceLine(); + o.body.sourceColumn = this.sourceColumn(); + o.body.sourceLineText = this.sourceLineText(); - // Add script information to the event if available. - var script = this.func().script(); - if (script) { - o.body.script = { name: script.name(), - lineOffset: script.lineOffset(), - columnOffset: script.columnOffset(), - lineCount: script.lineCount() - }; + // Add script information to the event if available. + var script = this.func().script(); + if (script) { + o.body.script = { name: script.name(), + lineOffset: script.lineOffset(), + columnOffset: script.columnOffset(), + lineCount: script.lineCount() + }; + } + } else { + o.body.sourceLine = -1; } - return SimpleObjectToJSON_(o); + return o.toJSONProtocol(); }; @@ -927,6 +931,25 @@ CompileEvent.prototype.script = function() { }; +CompileEvent.prototype.toJSONProtocol = function() { + var o = new ProtocolMessage(); + if (this.before_) { + o.event = "beforeCompile"; + } else { + o.event = "afterCompile"; + } + o.body = {}; + o.body.script = { name: this.script_.name(), + lineOffset: this.script_.lineOffset(), + columnOffset: this.script_.columnOffset(), + lineCount: this.script_.lineCount(), + source: this.script_.source() + }; + + return o.toJSONProtocol(); +} + + function MakeNewFunctionEvent(func) { return new NewFunctionEvent(func); } @@ -963,24 +986,32 @@ DebugCommandProcessor.prototype.processDebugRequest = function (request) { } -function ResponsePacket(request) { - // Build the initial response from the request. +function ProtocolMessage(request) { + // Update sequence number. this.seq = next_response_seq++; - this.type = 'response'; - if (request) this.request_seq = request.seq; - if (request) this.command = request.command; + + if (request) { + // If message is based on a request this is a response. Fill the initial + // response from the request. + this.type = 'response'; + this.request_seq = request.seq; + this.command = request.command; + } else { + // If message is not based on a request it is a dabugger generated event. + this.type = 'event'; + } this.success = true; this.running = false; } -ResponsePacket.prototype.failed = function(message) { +ProtocolMessage.prototype.failed = function(message) { this.success = false; this.message = message; } -ResponsePacket.prototype.toJSONProtocol = function() { +ProtocolMessage.prototype.toJSONProtocol = function() { // Encode the protocol header. var json = '{'; json += '"seq":' + this.seq; @@ -988,6 +1019,9 @@ ResponsePacket.prototype.toJSONProtocol = function() { json += ',"request_seq":' + this.request_seq; } json += ',"type":"' + this.type + '"'; + if (this.event) { + json += ',"event":' + StringToJSON_(this.event); + } if (this.command) { json += ',"command":' + StringToJSON_(this.command); } @@ -1033,7 +1067,7 @@ ResponsePacket.prototype.toJSONProtocol = function() { DebugCommandProcessor.prototype.createResponse = function(request) { - return new ResponsePacket(request); + return new ProtocolMessage(request); }; @@ -1652,7 +1686,9 @@ function SimpleObjectToJSON_(object, mirror_serializer) { var property_value_json; switch (typeof property_value) { case 'object': - if (typeof property_value.toJSONProtocol == 'function') { + if (property_value instanceof Mirror) { + property_value_json = mirror_serializer.serializeValue(property_value); + } else if (typeof property_value.toJSONProtocol == 'function') { property_value_json = property_value.toJSONProtocol(true) } else if (IS_ARRAY(property_value)){ property_value_json = SimpleArrayToJSON_(property_value, mirror_serializer);