This commit is contained in:
Alexey Andreev 2014-07-29 17:13:29 +04:00
parent ba9f6ef718
commit 81fff7a4a6
20 changed files with 87 additions and 25 deletions

View File

@ -20,7 +20,11 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.websocket.*; import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.teavm.chromerpd.data.CallFrameDTO; import org.teavm.chromerpd.data.CallFrameDTO;
@ -34,7 +38,7 @@ import org.teavm.debugging.*;
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@ClientEndpoint @ServerEndpoint("/")
public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger { public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger {
private List<JavaScriptDebuggerListener> listeners = new ArrayList<>(); private List<JavaScriptDebuggerListener> listeners = new ArrayList<>();
private Session session; private Session session;
@ -46,19 +50,25 @@ public class ChromeRDPDebuggerEndpoint implements JavaScriptDebugger {
private Map<Integer, Deferred> deferredResponses = new HashMap<>(); private Map<Integer, Deferred> deferredResponses = new HashMap<>();
private int messageIdGenerator; private int messageIdGenerator;
boolean closed; boolean closed;
private ChromeRDPContainer container;
@OnOpen @OnOpen
public void open(Session session) { public void open(Session session) {
this.session = session; this.session = session;
Object container = session.getUserProperties().get("container"); Object container = session.getUserProperties().get("rdp.container");
if (container instanceof ChromeRDPContainer) { if (container instanceof ChromeRDPContainer) {
((ChromeRDPContainer)container).setDebugger(this); this.container = (ChromeRDPContainer)container;
this.container.setDebugger(this);
} }
} }
@OnClose @OnClose
public void close() { public void close() {
closed = true; closed = true;
if (this.container != null) {
this.container.setDebugger(null);
this.container = null;
}
} }
@OnMessage @OnMessage

View File

@ -63,7 +63,7 @@ public class ChromeRDPServer {
} }
public void start() { public void start() {
Server server = new Server(); final Server server = new Server();
ServerConnector connector = new ServerConnector(server); ServerConnector connector = new ServerConnector(server);
connector.setPort(port); connector.setPort(port);
server.addConnector(connector); server.addConnector(connector);
@ -78,6 +78,7 @@ public class ChromeRDPServer {
wscontainer.addEndpoint(new RPDEndpointConfig()); wscontainer.addEndpoint(new RPDEndpointConfig());
server.start(); server.start();
server.dump(output); server.dump(output);
server.join();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -140,11 +141,15 @@ public class ChromeRDPServer {
} }
void setDebugger(JavaScriptDebugger debugger) { void setDebugger(JavaScriptDebugger debugger) {
if (!this.debugger.compareAndSet(null, debugger)) { if (debugger != null) {
throw new IllegalStateException("Can't handle more than one connection"); if (!this.debugger.compareAndSet(null, debugger)) {
} throw new IllegalStateException("Can't handle more than one connection");
for (ChromeRDPServerListener listener : listeners) { }
listener.connected(this); for (ChromeRDPServerListener listener : listeners) {
listener.connected(this);
}
} else {
this.debugger.set(null);
} }
} }
} }

View File

@ -15,10 +15,13 @@
*/ */
package org.teavm.chromerpd.data; package org.teavm.chromerpd.data;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class CallFrameDTO { public class CallFrameDTO {
private String callFrameId; private String callFrameId;
private LocationDTO location; private LocationDTO location;

View File

@ -15,10 +15,13 @@
*/ */
package org.teavm.chromerpd.data; package org.teavm.chromerpd.data;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class LocationDTO { public class LocationDTO {
private int columnNumber; private int columnNumber;
private int lineNumber; private int lineNumber;

View File

@ -16,11 +16,13 @@
package org.teavm.chromerpd.data; package org.teavm.chromerpd.data;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class Message { public class Message {
private Integer id; private Integer id;
private String method; private String method;

View File

@ -16,11 +16,13 @@
package org.teavm.chromerpd.data; package org.teavm.chromerpd.data;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class Response { public class Response {
private int id; private int id;
private JsonNode result; private JsonNode result;

View File

@ -15,12 +15,14 @@
*/ */
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerpd.data.LocationDTO; import org.teavm.chromerpd.data.LocationDTO;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class ContinueToLocationCommand { public class ContinueToLocationCommand {
private LocationDTO location; private LocationDTO location;

View File

@ -15,10 +15,13 @@
*/ */
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class RemoveBreakpointCommand { public class RemoveBreakpointCommand {
private String breakpointId; private String breakpointId;

View File

@ -15,10 +15,13 @@
*/ */
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScriptParsedNotification { public class ScriptParsedNotification {
private String scriptId; private String scriptId;
private String url; private String url;

View File

@ -15,12 +15,14 @@
*/ */
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerpd.data.LocationDTO; import org.teavm.chromerpd.data.LocationDTO;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class SetBreakpointCommand { public class SetBreakpointCommand {
private LocationDTO location; private LocationDTO location;

View File

@ -15,12 +15,14 @@
*/ */
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerpd.data.LocationDTO; import org.teavm.chromerpd.data.LocationDTO;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class SetBreakpointResponse { public class SetBreakpointResponse {
private String breakpointId; private String breakpointId;
private LocationDTO actualLocation; private LocationDTO actualLocation;

View File

@ -16,12 +16,14 @@
package org.teavm.chromerpd.messages; package org.teavm.chromerpd.messages;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerpd.data.CallFrameDTO; import org.teavm.chromerpd.data.CallFrameDTO;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class SuspendedNotification { public class SuspendedNotification {
private CallFrameDTO[] callFrames; private CallFrameDTO[] callFrames;
private String reason; private String reason;

View File

@ -4,6 +4,7 @@ chrome.browserAction.onClicked.addListener(function(tab) {
new DebuggerAgent(tab).attach(); new DebuggerAgent(tab).attach();
}); });
function DebuggerAgent(tab) { function DebuggerAgent(tab) {
this.pendingMessages = [];
this.connection = null; this.connection = null;
this.tab = null; this.tab = null;
this.debuggee = { tabId : tab.id }; this.debuggee = { tabId : tab.id };
@ -14,12 +15,12 @@ DebuggerAgent.prototype.attach = function() {
chrome.debugger.attach(this.debuggee, "1.0", (function(callback) { chrome.debugger.attach(this.debuggee, "1.0", (function(callback) {
this.attachedToDebugger = true; this.attachedToDebugger = true;
chrome.debugger.sendCommand(this.debuggee, "Debugger.enable", {}, callback); chrome.debugger.sendCommand(this.debuggee, "Debugger.enable", {}, callback);
}).bind(this, connectToServer.bind(this))); }).bind(this, this.connectToServer.bind(this)));
}; };
DebuggerAgent.prototype.connectToServer = function() { DebuggerAgent.prototype.connectToServer = function() {
this.connection = new WebSocket("ws://localhost:2357/"); this.connection = new WebSocket("ws://localhost:2357/");
this.connection.onmessage = function(event) { this.connection.onmessage = function(event) {
receiveMessage(this.debuggee, this.connection, JSON.parse(event.data)); this.receiveMessage(JSON.parse(event.data));
}.bind(this); }.bind(this);
this.connection.onclose = function(event) { this.connection.onclose = function(event) {
if (this.connection != null) { if (this.connection != null) {
@ -27,6 +28,12 @@ DebuggerAgent.prototype.connectToServer = function() {
this.disconnect(); this.disconnect();
} }
}.bind(this); }.bind(this);
this.connection.onopen = function() {
for (var i = 0; i < this.pendingMessages.length; ++i) {
this.connection.send(JSON.stringify(this.pendingMessages[i]));
}
this.pendingMessages = null;
}.bind(this);
}; };
DebuggerAgent.prototype.receiveMessage = function(message) { DebuggerAgent.prototype.receiveMessage = function(message) {
chrome.debugger.sendCommand(this.debuggee, message.method, message.params, function(response) { chrome.debugger.sendCommand(this.debuggee, message.method, message.params, function(response) {
@ -58,7 +65,11 @@ chrome.debugger.onEvent.addListener(function(source, method, params) {
return; return;
} }
var message = { method : method, params : params }; var message = { method : method, params : params };
this.connection.send(JSON.stringify(message)); if (agent.pendingMessages) {
agent.pendingMessages.push(message);
} else if (agent.connection) {
agent.connection.send(JSON.stringify(message));
}
}); });
chrome.debugger.onDetach.addListener(function(source) { chrome.debugger.onDetach.addListener(function(source) {
var agent = debuggerAgentMap[source.tabId]; var agent = debuggerAgentMap[source.tabId];

View File

@ -15,5 +15,5 @@
"background": { "background": {
"scripts": ["main.js"], "scripts": ["main.js"],
"persistent": false "persistent": false
}, }
} }

View File

@ -45,7 +45,7 @@ class DebugInformationReader {
} }
private int processSign(int number) { private int processSign(int number) {
boolean negative = (number & 1) == 1; boolean negative = (number & 1) != 0;
number >>>= 1; number >>>= 1;
return !negative ? number : -number; return !negative ? number : -number;
} }
@ -57,12 +57,12 @@ class DebugInformationReader {
last += lines[i]; last += lines[i];
lines[i] = last; lines[i] = last;
} }
int[] columns = new int[readUnsignedNumber()]; int[] columns = new int[lines.length];
resetRelativeNumber(); resetRelativeNumber();
for (int i = 0; i < columns.length; ++i) { for (int i = 0; i < columns.length; ++i) {
columns[i] = readRelativeNumber(); columns[i] = readRelativeNumber();
} }
int[] values = new int[readUnsignedNumber()]; int[] values = new int[lines.length];
resetRelativeNumber(); resetRelativeNumber();
for (int i = 0; i < values.length; ++i) { for (int i = 0; i < values.length; ++i) {
values[i] = readRelativeNumber(); values[i] = readRelativeNumber();
@ -88,7 +88,7 @@ class DebugInformationReader {
} }
n = processSign(n >>> 1); n = processSign(n >>> 1);
while (count-- > 0) { while (count-- > 0) {
array[i] = n; array[i++] = n;
} }
} }
return array; return array;
@ -100,13 +100,15 @@ class DebugInformationReader {
private int readUnsignedNumber() throws IOException { private int readUnsignedNumber() throws IOException {
int number = 0; int number = 0;
int shift = 0;
while (true) { while (true) {
int r = input.read(); int r = input.read();
if (r < 0) { if (r < 0) {
throw new EOFException(); throw new EOFException();
} }
byte b = (byte)r; byte b = (byte)r;
number = (number << 7) | (b & 0x7F); number |= (b & 0x7F) << shift;
shift += 7;
if ((b & 0x80) == 0) { if ((b & 0x80) == 0) {
break; break;
} }

View File

@ -49,7 +49,6 @@ class DebugInformationWriter {
} }
private void writeMapping(DebugInformation.Mapping mapping) throws IOException { private void writeMapping(DebugInformation.Mapping mapping) throws IOException {
writeUnsignedNumber(mapping.lines.length);
int[] lines = mapping.lines.clone(); int[] lines = mapping.lines.clone();
int last = 0; int last = 0;
for (int i = 0; i < lines.length; ++i) { for (int i = 0; i < lines.length; ++i) {

View File

@ -165,6 +165,9 @@ public class Debugger {
return; return;
} }
DebugInformation debugInfo = debugInformationProvider.getDebugInformation(name); DebugInformation debugInfo = debugInformationProvider.getDebugInformation(name);
if (debugInfo == null) {
return;
}
debugInformationMap.put(name, debugInfo); debugInformationMap.put(name, debugInfo);
for (String sourceFile : debugInfo.getCoveredSourceFiles()) { for (String sourceFile : debugInfo.getCoveredSourceFiles()) {
List<DebugInformation> list = debugInformationFileMap.get(sourceFile); List<DebugInformation> list = debugInformationFileMap.get(sourceFile);

View File

@ -36,4 +36,9 @@ public class SourceLocation {
public int getLine() { public int getLine() {
return line; return line;
} }
@Override
public String toString() {
return fileName + ":" + line;
}
} }

View File

@ -33,7 +33,7 @@ public class URLDebugInformationProvider implements DebugInformationProvider {
@Override @Override
public DebugInformation getDebugInformation(String script) { public DebugInformation getDebugInformation(String script) {
try { try {
URL url = new URL(baseURL + script); URL url = new URL(baseURL + script + ".teavmdbg");
try (InputStream input = url.openStream()) { try (InputStream input = url.openStream()) {
return DebugInformation.read(input); return DebugInformation.read(input);
} }

View File

@ -495,13 +495,16 @@ class StatementGenerator implements InstructionVisitor {
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
Expr right = Expr.var(insn.getValue().getIndex());
Expr left;
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
assign(Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()), insn.getValue().getIndex()); left = Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField());
} else { } else {
Expr fieldExpr = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())), left = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())), insn.getField());
insn.getField());
assign(fieldExpr, insn.getValue().getIndex());
} }
AssignmentStatement stmt = Statement.assign(left, right);
stmt.setLocation(currentLocation);
statements.add(stmt);
} }
@Override @Override