mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Adds support of object's fields in debugger watches
This commit is contained in:
parent
8d0432dd5e
commit
461528b51f
|
@ -63,11 +63,14 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
private ChromeRDPExchangeListener exchangeListener = new ChromeRDPExchangeListener() {
|
private ChromeRDPExchangeListener exchangeListener = new ChromeRDPExchangeListener() {
|
||||||
@Override public void received(String messageText) throws IOException {
|
@Override public void received(String messageText) throws IOException {
|
||||||
JsonNode jsonMessage = mapper.readTree(messageText);
|
JsonNode jsonMessage = mapper.readTree(messageText);
|
||||||
if (jsonMessage.has("result")) {
|
if (jsonMessage.has("id")) {
|
||||||
Response response = mapper.reader(Response.class).readValue(jsonMessage);
|
Response response = mapper.reader(Response.class).readValue(jsonMessage);
|
||||||
responseHandlers.remove(response.getId()).received(response.getResult());
|
responseHandlers.remove(response.getId()).received(response.getResult());
|
||||||
} else {
|
} else {
|
||||||
Message message = mapper.reader(Message.class).readValue(messageText);
|
Message message = mapper.reader(Message.class).readValue(messageText);
|
||||||
|
if (message.getMethod() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (message.getMethod()) {
|
switch (message.getMethod()) {
|
||||||
case "Debugger.paused":
|
case "Debugger.paused":
|
||||||
firePaused(parseJson(SuspendedNotification.class, message.getParams()));
|
firePaused(parseJson(SuspendedNotification.class, message.getParams()));
|
||||||
|
@ -290,6 +293,40 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getClassName(String objectId) {
|
||||||
|
if (exchange == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Message message = new Message();
|
||||||
|
message.setId(messageIdGenerator.incrementAndGet());
|
||||||
|
message.setMethod("Runtime.callFunctionOn");
|
||||||
|
CallFunctionCommand params = new CallFunctionCommand();
|
||||||
|
CallArgumentDTO arg = new CallArgumentDTO();
|
||||||
|
arg.setObjectId(objectId);
|
||||||
|
params.setObjectId(objectId);
|
||||||
|
params.setArguments(new CallArgumentDTO[] { arg });
|
||||||
|
params.setFunctionDeclaration("$dbg_class");
|
||||||
|
message.setParams(mapper.valueToTree(params));
|
||||||
|
final BlockingQueue<String> sync = new LinkedTransferQueue<>();
|
||||||
|
responseHandlers.put(message.getId(), new ResponseHandler() {
|
||||||
|
@Override public void received(JsonNode node) throws IOException {
|
||||||
|
if (node == null) {
|
||||||
|
sync.add("");
|
||||||
|
} else {
|
||||||
|
CallFunctionResponse response = mapper.reader(CallFunctionResponse.class).readValue(node);
|
||||||
|
sync.add(response.getResult().getValue().getTextValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sendMessage(message);
|
||||||
|
try {
|
||||||
|
String result = sync.take();
|
||||||
|
return result.isEmpty() ? null : result;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<RDPLocalVariable> parseProperties(PropertyDescriptorDTO[] properties) {
|
private List<RDPLocalVariable> parseProperties(PropertyDescriptorDTO[] properties) {
|
||||||
List<RDPLocalVariable> variables = new ArrayList<>();
|
List<RDPLocalVariable> variables = new ArrayList<>();
|
||||||
if (properties != null) {
|
if (properties != null) {
|
||||||
|
@ -298,14 +335,16 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
RDPValue value;
|
RDPValue value;
|
||||||
switch (remoteValue.getType()) {
|
switch (remoteValue.getType()) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
value = new RDPValue("undefined");
|
value = new RDPValue(this, "undefined", "undefined", null);
|
||||||
break;
|
break;
|
||||||
case "object":
|
case "object":
|
||||||
case "function":
|
case "function":
|
||||||
value = new RDPValue(remoteValue.getObjectId());
|
value = new RDPValue(this, remoteValue.getDescription(), remoteValue.getType(),
|
||||||
|
remoteValue.getObjectId());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
value = new RDPValue(remoteValue.getValue().asText());
|
value = new RDPValue(this, remoteValue.getValue().asText(), remoteValue.getType(),
|
||||||
|
remoteValue.getObjectId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,14 @@ import java.util.AbstractMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
||||||
private volatile Map<String, RDPLocalVariable> backingMap;
|
private AtomicReference<Map<String, RDPLocalVariable>> backingMap = new AtomicReference<>();
|
||||||
private ChromeRDPDebugger debugger;
|
private ChromeRDPDebugger debugger;
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
|
@ -22,32 +23,31 @@ public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
||||||
@Override
|
@Override
|
||||||
public Set<Entry<String, RDPLocalVariable>> entrySet() {
|
public Set<Entry<String, RDPLocalVariable>> entrySet() {
|
||||||
initBackingMap();
|
initBackingMap();
|
||||||
return backingMap.entrySet();
|
return backingMap.get().entrySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
initBackingMap();
|
initBackingMap();
|
||||||
return backingMap.size();
|
return backingMap.get().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RDPLocalVariable get(Object key) {
|
public RDPLocalVariable get(Object key) {
|
||||||
initBackingMap();
|
initBackingMap();
|
||||||
return backingMap.get(key);
|
return backingMap.get().get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initBackingMap() {
|
private void initBackingMap() {
|
||||||
if (backingMap != null) {
|
if (backingMap.get() != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (id == null) {
|
|
||||||
backingMap = new HashMap<>();
|
|
||||||
}
|
|
||||||
Map<String, RDPLocalVariable> newBackingMap = new HashMap<>();
|
Map<String, RDPLocalVariable> newBackingMap = new HashMap<>();
|
||||||
|
if (id != null) {
|
||||||
for (RDPLocalVariable variable : debugger.getScope(id)) {
|
for (RDPLocalVariable variable : debugger.getScope(id)) {
|
||||||
newBackingMap.put(variable.getName(), variable);
|
newBackingMap.put(variable.getName(), variable);
|
||||||
}
|
}
|
||||||
backingMap = newBackingMap;
|
}
|
||||||
|
backingMap.compareAndSet(null, newBackingMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,18 @@ import org.teavm.debugging.JavaScriptVariable;
|
||||||
*/
|
*/
|
||||||
public class RDPValue implements JavaScriptValue {
|
public class RDPValue implements JavaScriptValue {
|
||||||
private String representation;
|
private String representation;
|
||||||
|
private String typeName;
|
||||||
|
private ChromeRDPDebugger debugger;
|
||||||
|
private String objectId;
|
||||||
|
private Map<String, ? extends JavaScriptVariable> properties;
|
||||||
|
|
||||||
public RDPValue(String representation) {
|
public RDPValue(ChromeRDPDebugger debugger, String representation, String typeName, String objectId) {
|
||||||
this.representation = representation;
|
this.representation = representation;
|
||||||
|
this.typeName = typeName;
|
||||||
|
this.debugger = debugger;
|
||||||
|
this.objectId = objectId;
|
||||||
|
properties = objectId != null ? new RDPScope(debugger, objectId) :
|
||||||
|
Collections.<String, RDPLocalVariable>emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,8 +30,19 @@ public class RDPValue implements JavaScriptValue {
|
||||||
return representation;
|
return representation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClassName() {
|
||||||
|
if (objectId != null) {
|
||||||
|
String className = debugger.getClassName(objectId);
|
||||||
|
return className != null ? className : "object";
|
||||||
|
} else {
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Map<String, JavaScriptVariable> getProperties() {
|
public Map<String, JavaScriptVariable> getProperties() {
|
||||||
return Collections.emptyMap();
|
return (Map<String, JavaScriptVariable>)properties;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.teavm.chromerdp.data;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.JsonNode;
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class CallArgumentDTO {
|
||||||
|
private String objectId;
|
||||||
|
private JsonNode value;
|
||||||
|
|
||||||
|
public String getObjectId() {
|
||||||
|
return objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectId(String objectId) {
|
||||||
|
this.objectId = objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonNode getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(JsonNode value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package org.teavm.chromerdp.messages;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
import org.teavm.chromerdp.data.CallArgumentDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class CallFunctionCommand {
|
||||||
|
private String objectId;
|
||||||
|
private String functionDeclaration;
|
||||||
|
private CallArgumentDTO[] arguments;
|
||||||
|
private boolean returnByValue;
|
||||||
|
|
||||||
|
public String getObjectId() {
|
||||||
|
return objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectId(String objectId) {
|
||||||
|
this.objectId = objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFunctionDeclaration() {
|
||||||
|
return functionDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFunctionDeclaration(String functionDeclaration) {
|
||||||
|
this.functionDeclaration = functionDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallArgumentDTO[] getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArguments(CallArgumentDTO[] arguments) {
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReturnByValue() {
|
||||||
|
return returnByValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReturnByValue(boolean returnByValue) {
|
||||||
|
this.returnByValue = returnByValue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.teavm.chromerdp.messages;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||||
|
import org.teavm.chromerdp.data.RemoteObjectDTO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class CallFunctionResponse {
|
||||||
|
private RemoteObjectDTO result;
|
||||||
|
private boolean wasThrown;
|
||||||
|
|
||||||
|
public RemoteObjectDTO getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(RemoteObjectDTO result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWasThrown() {
|
||||||
|
return wasThrown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWasThrown(boolean wasThrown) {
|
||||||
|
this.wasThrown = wasThrown;
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,8 @@ DebuggerAgent.prototype.connectToServer = function() {
|
||||||
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) {
|
||||||
if (message.id) {
|
if (message.id) {
|
||||||
var responseToServer = { id : message.id, result : response };
|
var responseToServer = { id : message.id, result : response,
|
||||||
|
error : response ? undefined : chrome.runtime.lastError };
|
||||||
this.connection.send(JSON.stringify(responseToServer));
|
this.connection.send(JSON.stringify(responseToServer));
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
|
@ -33,6 +33,8 @@ public class DebugInformation {
|
||||||
Map<String, Integer> fileNameMap;
|
Map<String, Integer> fileNameMap;
|
||||||
String[] classNames;
|
String[] classNames;
|
||||||
Map<String, Integer> classNameMap;
|
Map<String, Integer> classNameMap;
|
||||||
|
String[] fields;
|
||||||
|
Map<String, Integer> fieldMap;
|
||||||
String[] methods;
|
String[] methods;
|
||||||
Map<String, Integer> methodMap;
|
Map<String, Integer> methodMap;
|
||||||
String[] variableNames;
|
String[] variableNames;
|
||||||
|
@ -43,6 +45,7 @@ public class DebugInformation {
|
||||||
Mapping methodMapping;
|
Mapping methodMapping;
|
||||||
Mapping lineMapping;
|
Mapping lineMapping;
|
||||||
Mapping[] variableMappings;
|
Mapping[] variableMappings;
|
||||||
|
List<Map<Integer, Integer>> classesMetadata;
|
||||||
|
|
||||||
public String[] getCoveredSourceFiles() {
|
public String[] getCoveredSourceFiles() {
|
||||||
return fileNames.clone();
|
return fileNames.clone();
|
||||||
|
@ -118,6 +121,19 @@ public class DebugInformation {
|
||||||
return componentByKey(mapping, variableNames, location);
|
return componentByKey(mapping, variableNames, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFieldMeaning(String className, String jsName) {
|
||||||
|
Integer classIndex = classNameMap.get(className);
|
||||||
|
if (classIndex == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Integer jsIndex = fieldMap.get(jsName);
|
||||||
|
if (jsIndex == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Integer fieldIndex = classesMetadata.get(classIndex).get(jsIndex);
|
||||||
|
return fieldIndex != null ? fields[fieldIndex] : null;
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
|
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
|
||||||
int keyIndex = indexByKey(mapping, location);
|
int keyIndex = indexByKey(mapping, location);
|
||||||
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
|
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
|
||||||
|
@ -142,6 +158,7 @@ public class DebugInformation {
|
||||||
void rebuildMaps() {
|
void rebuildMaps() {
|
||||||
fileNameMap = mapArray(fileNames);
|
fileNameMap = mapArray(fileNames);
|
||||||
classNameMap = mapArray(classNames);
|
classNameMap = mapArray(classNames);
|
||||||
|
fieldMap = mapArray(fields);
|
||||||
methodMap = mapArray(methods);
|
methodMap = mapArray(methods);
|
||||||
variableNameMap = mapArray(variableNames);
|
variableNameMap = mapArray(variableNames);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
private DebugInformation debugInformation;
|
private DebugInformation debugInformation;
|
||||||
private MappedList files = new MappedList();
|
private MappedList files = new MappedList();
|
||||||
private MappedList classes = new MappedList();
|
private MappedList classes = new MappedList();
|
||||||
|
private MappedList fields = new MappedList();
|
||||||
private MappedList methods = new MappedList();
|
private MappedList methods = new MappedList();
|
||||||
private MappedList variableNames = new MappedList();
|
private MappedList variableNames = new MappedList();
|
||||||
private Mapping fileMapping = new Mapping();
|
private Mapping fileMapping = new Mapping();
|
||||||
|
@ -39,6 +40,8 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
private MethodDescriptor currentMethod;
|
private MethodDescriptor currentMethod;
|
||||||
private String currentClass;
|
private String currentClass;
|
||||||
private String currentFileName;
|
private String currentFileName;
|
||||||
|
private int currentClassMetadata = -1;
|
||||||
|
private List<ClassMetadata> classesMetadata = new ArrayList<>();
|
||||||
private int currentLine;
|
private int currentLine;
|
||||||
|
|
||||||
public LocationProvider getLocationProvider() {
|
public LocationProvider getLocationProvider() {
|
||||||
|
@ -96,18 +99,32 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
mapping.add(locationProvider, sourceIndex);
|
mapping.add(locationProvider, sourceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClass(String className) {
|
||||||
|
int classIndex = classes.index(className);
|
||||||
|
while (classIndex >= classesMetadata.size()) {
|
||||||
|
classesMetadata.add(new ClassMetadata());
|
||||||
|
}
|
||||||
|
currentClassMetadata = classIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addField(String fieldName, String jsName) {
|
||||||
|
ClassMetadata metadata = classesMetadata.get(currentClassMetadata);
|
||||||
|
int fieldIndex = fields.index(fieldName);
|
||||||
|
int jsIndex = fields.index(jsName);
|
||||||
|
metadata.fieldMap.put(jsIndex, fieldIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public DebugInformation getDebugInformation() {
|
public DebugInformation getDebugInformation() {
|
||||||
if (debugInformation == null) {
|
if (debugInformation == null) {
|
||||||
debugInformation = new DebugInformation();
|
debugInformation = new DebugInformation();
|
||||||
|
|
||||||
debugInformation.fileNames = files.getItems();
|
debugInformation.fileNames = files.getItems();;
|
||||||
debugInformation.fileNameMap = files.getIndexes();
|
|
||||||
debugInformation.classNames = classes.getItems();
|
debugInformation.classNames = classes.getItems();
|
||||||
debugInformation.classNameMap = classes.getIndexes();
|
debugInformation.fields = fields.getItems();
|
||||||
debugInformation.methods = methods.getItems();
|
debugInformation.methods = methods.getItems();
|
||||||
debugInformation.methodMap = methods.getIndexes();
|
|
||||||
debugInformation.variableNames = variableNames.getItems();
|
debugInformation.variableNames = variableNames.getItems();
|
||||||
debugInformation.variableNameMap = variableNames.getIndexes();
|
|
||||||
|
|
||||||
debugInformation.fileMapping = fileMapping.build();
|
debugInformation.fileMapping = fileMapping.build();
|
||||||
debugInformation.lineMapping = lineMapping.build();
|
debugInformation.lineMapping = lineMapping.build();
|
||||||
|
@ -119,7 +136,19 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
debugInformation.variableMappings[var] = mapping.build();
|
debugInformation.variableMappings[var] = mapping.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Map<Integer, Integer>> builtMetadata = new ArrayList<>(classes.list.size());
|
||||||
|
for (int i = 0; i < classes.list.size(); ++i) {
|
||||||
|
if (i >= classesMetadata.size()) {
|
||||||
|
builtMetadata.add(new HashMap<Integer, Integer>());
|
||||||
|
} else {
|
||||||
|
Map<Integer, Integer> map = new HashMap<>(classesMetadata.get(i).fieldMap);
|
||||||
|
builtMetadata.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debugInformation.classesMetadata = builtMetadata;
|
||||||
|
|
||||||
debugInformation.rebuildFileDescriptions();
|
debugInformation.rebuildFileDescriptions();
|
||||||
|
debugInformation.rebuildMaps();
|
||||||
}
|
}
|
||||||
return debugInformation;
|
return debugInformation;
|
||||||
}
|
}
|
||||||
|
@ -172,4 +201,8 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
return new HashMap<>(map);
|
return new HashMap<>(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ClassMetadata {
|
||||||
|
Map<Integer, Integer> fieldMap = new HashMap<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,4 +32,8 @@ public interface DebugInformationEmitter {
|
||||||
void emitClass(String className);
|
void emitClass(String className);
|
||||||
|
|
||||||
void emitVariable(String sourceName, String generatedName);
|
void emitVariable(String sourceName, String generatedName);
|
||||||
|
|
||||||
|
void addClass(String className);
|
||||||
|
|
||||||
|
void addField(String fieldName, String jsName);
|
||||||
}
|
}
|
|
@ -18,6 +18,10 @@ package org.teavm.debugging;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -35,6 +39,7 @@ class DebugInformationReader {
|
||||||
DebugInformation debugInfo = new DebugInformation();
|
DebugInformation debugInfo = new DebugInformation();
|
||||||
debugInfo.fileNames = readStrings();
|
debugInfo.fileNames = readStrings();
|
||||||
debugInfo.classNames = readStrings();
|
debugInfo.classNames = readStrings();
|
||||||
|
debugInfo.fields = readStrings();
|
||||||
debugInfo.methods = readStrings();
|
debugInfo.methods = readStrings();
|
||||||
debugInfo.variableNames = readStrings();
|
debugInfo.variableNames = readStrings();
|
||||||
debugInfo.fileMapping = readMapping();
|
debugInfo.fileMapping = readMapping();
|
||||||
|
@ -42,6 +47,7 @@ class DebugInformationReader {
|
||||||
debugInfo.classMapping = readMapping();
|
debugInfo.classMapping = readMapping();
|
||||||
debugInfo.methodMapping = readMapping();
|
debugInfo.methodMapping = readMapping();
|
||||||
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
|
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
|
||||||
|
debugInfo.classesMetadata = readClassesMetadata(debugInfo.classNames.length);
|
||||||
debugInfo.rebuildFileDescriptions();
|
debugInfo.rebuildFileDescriptions();
|
||||||
debugInfo.rebuildMaps();
|
debugInfo.rebuildMaps();
|
||||||
return debugInfo;
|
return debugInfo;
|
||||||
|
@ -58,6 +64,22 @@ class DebugInformationReader {
|
||||||
return mappings;
|
return mappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Map<Integer, Integer>> readClassesMetadata(int count) throws IOException {
|
||||||
|
List<Map<Integer, Integer>> classes = new ArrayList<>(count);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
Map<Integer, Integer> cls = new HashMap<>();
|
||||||
|
classes.add(cls);
|
||||||
|
int entryCount = readUnsignedNumber();
|
||||||
|
resetRelativeNumber();
|
||||||
|
for (int j = 0; j < entryCount; ++j) {
|
||||||
|
int key = readRelativeNumber();
|
||||||
|
int value = readUnsignedNumber();
|
||||||
|
cls.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
private int processSign(int number) {
|
private int processSign(int number) {
|
||||||
boolean negative = (number & 1) != 0;
|
boolean negative = (number & 1) != 0;
|
||||||
number >>>= 1;
|
number >>>= 1;
|
||||||
|
|
|
@ -17,6 +17,10 @@ package org.teavm.debugging;
|
||||||
|
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -33,6 +37,7 @@ class DebugInformationWriter {
|
||||||
public void write(DebugInformation debugInfo) throws IOException {
|
public void write(DebugInformation debugInfo) throws IOException {
|
||||||
writeStringArray(debugInfo.fileNames);
|
writeStringArray(debugInfo.fileNames);
|
||||||
writeStringArray(debugInfo.classNames);
|
writeStringArray(debugInfo.classNames);
|
||||||
|
writeStringArray(debugInfo.fields);
|
||||||
writeStringArray(debugInfo.methods);
|
writeStringArray(debugInfo.methods);
|
||||||
writeStringArray(debugInfo.variableNames);
|
writeStringArray(debugInfo.variableNames);
|
||||||
|
|
||||||
|
@ -41,6 +46,7 @@ class DebugInformationWriter {
|
||||||
writeMapping(debugInfo.classMapping);
|
writeMapping(debugInfo.classMapping);
|
||||||
writeMapping(debugInfo.methodMapping);
|
writeMapping(debugInfo.methodMapping);
|
||||||
writeVariableMappings(debugInfo);
|
writeVariableMappings(debugInfo);
|
||||||
|
writeClassMetadata(debugInfo.classesMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeVariableMappings(DebugInformation debugInfo) throws IOException {
|
private void writeVariableMappings(DebugInformation debugInfo) throws IOException {
|
||||||
|
@ -57,6 +63,20 @@ class DebugInformationWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeClassMetadata(List<Map<Integer, Integer>> classes) throws IOException {
|
||||||
|
for (int i = 0; i < classes.size(); ++i) {
|
||||||
|
Map<Integer, Integer> cls = classes.get(i);
|
||||||
|
writeUnsignedNumber(cls.size());
|
||||||
|
List<Integer> keys = new ArrayList<>(cls.keySet());
|
||||||
|
Collections.sort(keys);
|
||||||
|
resetRelativeNumber();
|
||||||
|
for (int key : keys) {
|
||||||
|
writeRelativeNumber(key);
|
||||||
|
writeUnsignedNumber(cls.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int nonNullVariableMappings(DebugInformation debugInfo) {
|
private int nonNullVariableMappings(DebugInformation debugInfo) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
|
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
|
||||||
|
|
|
@ -288,6 +288,16 @@ public class Debugger {
|
||||||
return debugInfo.getVariableMeaningAt(location.getLine(), location.getColumn(), variable);
|
return debugInfo.getVariableMeaningAt(location.getLine(), location.getColumn(), variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String mapField(String className, String jsField) {
|
||||||
|
for (DebugInformation debugInfo : debugInformationMap.values()) {
|
||||||
|
String meaning = debugInfo.getFieldMeaning(className, jsField);
|
||||||
|
if (meaning != null) {
|
||||||
|
return meaning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private JavaScriptDebuggerListener javaScriptListener = new JavaScriptDebuggerListener() {
|
private JavaScriptDebuggerListener javaScriptListener = new JavaScriptDebuggerListener() {
|
||||||
@Override
|
@Override
|
||||||
public void resumed() {
|
public void resumed() {
|
||||||
|
|
|
@ -43,4 +43,12 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
||||||
@Override
|
@Override
|
||||||
public void setLocationProvider(LocationProvider locationProvider) {
|
public void setLocationProvider(LocationProvider locationProvider) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClass(String className) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addField(String fieldName, String jsName) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,5 +24,7 @@ import java.util.Map;
|
||||||
public interface JavaScriptValue {
|
public interface JavaScriptValue {
|
||||||
String getRepresentation();
|
String getRepresentation();
|
||||||
|
|
||||||
|
String getClassName();
|
||||||
|
|
||||||
Map<String, JavaScriptVariable> getProperties();
|
Map<String, JavaScriptVariable> getProperties();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.teavm.debugging;
|
||||||
|
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
|
*/
|
||||||
|
class PropertyMap extends AbstractMap<String, Variable>{
|
||||||
|
private String className;
|
||||||
|
private AtomicReference<Map<String, Variable>> backingMap = new AtomicReference<>();
|
||||||
|
private Map<String, JavaScriptVariable> jsVariables;
|
||||||
|
private Debugger debugger;
|
||||||
|
|
||||||
|
public PropertyMap(String className, Map<String, JavaScriptVariable> jsVariables, Debugger debugger) {
|
||||||
|
this.className = className;
|
||||||
|
this.jsVariables = jsVariables;
|
||||||
|
this.debugger = debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
updateBackingMap();
|
||||||
|
return backingMap.get().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Variable get(Object key) {
|
||||||
|
updateBackingMap();
|
||||||
|
return backingMap.get().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entry<String, Variable>> entrySet() {
|
||||||
|
updateBackingMap();
|
||||||
|
return backingMap.get().entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBackingMap() {
|
||||||
|
if (backingMap.get() != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, Variable> vars = new HashMap<>();
|
||||||
|
for (Map.Entry<String, JavaScriptVariable> entry : jsVariables.entrySet()) {
|
||||||
|
JavaScriptVariable jsVar = entry.getValue();
|
||||||
|
String name = debugger.mapField(className, entry.getKey());
|
||||||
|
if (name == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Value value = new Value(debugger, jsVar.getValue());
|
||||||
|
vars.put(entry.getKey(), new Variable(name, value));
|
||||||
|
}
|
||||||
|
backingMap.compareAndSet(null, vars);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014 Alexey Andreev.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.teavm.debugging;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
class SimpleValue extends Value {
|
|
||||||
private String representation;
|
|
||||||
|
|
||||||
public SimpleValue(String representation) {
|
|
||||||
this.representation = representation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRepresentation() {
|
|
||||||
return representation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Variable> getProperties() {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,13 +16,34 @@
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public abstract class Value {
|
public class Value {
|
||||||
public abstract String getRepresentation();
|
private Debugger debugger;
|
||||||
|
private JavaScriptValue jsValue;
|
||||||
|
private AtomicReference<PropertyMap> properties = new AtomicReference<>();
|
||||||
|
|
||||||
public abstract Map<String, Variable> getProperties();
|
Value(Debugger debugger, JavaScriptValue jsValue) {
|
||||||
|
this.debugger = debugger;
|
||||||
|
this.jsValue = jsValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRepresentation() {
|
||||||
|
return jsValue.getRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return jsValue.getClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Variable> getProperties() {
|
||||||
|
if (properties.get() == null) {
|
||||||
|
properties.compareAndSet(null, new PropertyMap(jsValue.getClassName(), jsValue.getProperties(), debugger));
|
||||||
|
}
|
||||||
|
return properties.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ class VariableMap extends AbstractMap<String, Variable> {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SimpleValue value = new SimpleValue(jsVar.getValue().getRepresentation());
|
Value value = new Value(debugger, jsVar.getValue());
|
||||||
vars.put(entry.getKey(), new Variable(name, value));
|
vars.put(entry.getKey(), new Variable(name, value));
|
||||||
}
|
}
|
||||||
backingMap.compareAndSet(null, vars);
|
backingMap.compareAndSet(null, vars);
|
||||||
|
|
|
@ -243,6 +243,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
|
|
||||||
public void render(ClassNode cls) throws RenderingException {
|
public void render(ClassNode cls) throws RenderingException {
|
||||||
debugEmitter.emitClass(cls.getName());
|
debugEmitter.emitClass(cls.getName());
|
||||||
|
debugEmitter.addClass(cls.getName());
|
||||||
try {
|
try {
|
||||||
writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{")
|
writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{")
|
||||||
.indent().softNewLine();
|
.indent().softNewLine();
|
||||||
|
@ -254,8 +255,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = getDefaultValue(field.getType());
|
value = getDefaultValue(field.getType());
|
||||||
}
|
}
|
||||||
writer.append("this.").appendField(new FieldReference(cls.getName(), field.getName())).ws()
|
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
|
||||||
.append("=").ws().append(constantToString(value)).append(";").softNewLine();
|
writer.append("this.").appendField(fieldRef).ws().append("=").ws().append(constantToString(value))
|
||||||
|
.append(";").softNewLine();
|
||||||
|
debugEmitter.addField(field.getName(), naming.getNameFor(fieldRef));
|
||||||
}
|
}
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
|
|
||||||
|
@ -267,8 +270,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
value = getDefaultValue(field.getType());
|
value = getDefaultValue(field.getType());
|
||||||
}
|
}
|
||||||
writer.appendClass(cls.getName()).append('.')
|
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
|
||||||
.appendField(new FieldReference(cls.getName(), field.getName())).ws().append("=").ws()
|
writer.appendClass(cls.getName()).append('.').appendField(fieldRef).ws().append("=").ws()
|
||||||
.append(constantToString(value)).append(";").softNewLine();
|
.append(constantToString(value)).append(";").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,7 +398,8 @@ function $dbg_class(obj) {
|
||||||
if (obj instanceof Long) {
|
if (obj instanceof Long) {
|
||||||
return "long";
|
return "long";
|
||||||
}
|
}
|
||||||
return obj.constructor.$meta.name;
|
var meta = obj.constructor.$meta;
|
||||||
|
return meta ? meta.name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Long = function(lo, hi) {
|
Long = function(lo, hi) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user