mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -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() {
|
||||
@Override public void received(String messageText) throws IOException {
|
||||
JsonNode jsonMessage = mapper.readTree(messageText);
|
||||
if (jsonMessage.has("result")) {
|
||||
if (jsonMessage.has("id")) {
|
||||
Response response = mapper.reader(Response.class).readValue(jsonMessage);
|
||||
responseHandlers.remove(response.getId()).received(response.getResult());
|
||||
} else {
|
||||
Message message = mapper.reader(Message.class).readValue(messageText);
|
||||
if (message.getMethod() == null) {
|
||||
return;
|
||||
}
|
||||
switch (message.getMethod()) {
|
||||
case "Debugger.paused":
|
||||
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) {
|
||||
List<RDPLocalVariable> variables = new ArrayList<>();
|
||||
if (properties != null) {
|
||||
|
@ -298,14 +335,16 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
RDPValue value;
|
||||
switch (remoteValue.getType()) {
|
||||
case "undefined":
|
||||
value = new RDPValue("undefined");
|
||||
value = new RDPValue(this, "undefined", "undefined", null);
|
||||
break;
|
||||
case "object":
|
||||
case "function":
|
||||
value = new RDPValue(remoteValue.getObjectId());
|
||||
value = new RDPValue(this, remoteValue.getDescription(), remoteValue.getType(),
|
||||
remoteValue.getObjectId());
|
||||
break;
|
||||
default:
|
||||
value = new RDPValue(remoteValue.getValue().asText());
|
||||
value = new RDPValue(this, remoteValue.getValue().asText(), remoteValue.getType(),
|
||||
remoteValue.getObjectId());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ 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>
|
||||
*/
|
||||
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 String id;
|
||||
|
||||
|
@ -22,32 +23,31 @@ public class RDPScope extends AbstractMap<String, RDPLocalVariable> {
|
|||
@Override
|
||||
public Set<Entry<String, RDPLocalVariable>> entrySet() {
|
||||
initBackingMap();
|
||||
return backingMap.entrySet();
|
||||
return backingMap.get().entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
initBackingMap();
|
||||
return backingMap.size();
|
||||
return backingMap.get().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RDPLocalVariable get(Object key) {
|
||||
initBackingMap();
|
||||
return backingMap.get(key);
|
||||
return backingMap.get().get(key);
|
||||
}
|
||||
|
||||
private void initBackingMap() {
|
||||
if (backingMap != null) {
|
||||
if (backingMap.get() != null) {
|
||||
return;
|
||||
}
|
||||
if (id == null) {
|
||||
backingMap = new HashMap<>();
|
||||
}
|
||||
Map<String, RDPLocalVariable> newBackingMap = new HashMap<>();
|
||||
if (id != null) {
|
||||
for (RDPLocalVariable variable : debugger.getScope(id)) {
|
||||
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 {
|
||||
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.typeName = typeName;
|
||||
this.debugger = debugger;
|
||||
this.objectId = objectId;
|
||||
properties = objectId != null ? new RDPScope(debugger, objectId) :
|
||||
Collections.<String, RDPLocalVariable>emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,8 +30,19 @@ public class RDPValue implements JavaScriptValue {
|
|||
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
|
||||
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) {
|
||||
chrome.debugger.sendCommand(this.debuggee, message.method, message.params, function(response) {
|
||||
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));
|
||||
}
|
||||
}.bind(this));
|
||||
|
|
|
@ -33,6 +33,8 @@ public class DebugInformation {
|
|||
Map<String, Integer> fileNameMap;
|
||||
String[] classNames;
|
||||
Map<String, Integer> classNameMap;
|
||||
String[] fields;
|
||||
Map<String, Integer> fieldMap;
|
||||
String[] methods;
|
||||
Map<String, Integer> methodMap;
|
||||
String[] variableNames;
|
||||
|
@ -43,6 +45,7 @@ public class DebugInformation {
|
|||
Mapping methodMapping;
|
||||
Mapping lineMapping;
|
||||
Mapping[] variableMappings;
|
||||
List<Map<Integer, Integer>> classesMetadata;
|
||||
|
||||
public String[] getCoveredSourceFiles() {
|
||||
return fileNames.clone();
|
||||
|
@ -118,6 +121,19 @@ public class DebugInformation {
|
|||
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) {
|
||||
int keyIndex = indexByKey(mapping, location);
|
||||
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
|
||||
|
@ -142,6 +158,7 @@ public class DebugInformation {
|
|||
void rebuildMaps() {
|
||||
fileNameMap = mapArray(fileNames);
|
||||
classNameMap = mapArray(classNames);
|
||||
fieldMap = mapArray(fields);
|
||||
methodMap = mapArray(methods);
|
||||
variableNameMap = mapArray(variableNames);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
private DebugInformation debugInformation;
|
||||
private MappedList files = new MappedList();
|
||||
private MappedList classes = new MappedList();
|
||||
private MappedList fields = new MappedList();
|
||||
private MappedList methods = new MappedList();
|
||||
private MappedList variableNames = new MappedList();
|
||||
private Mapping fileMapping = new Mapping();
|
||||
|
@ -39,6 +40,8 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
private MethodDescriptor currentMethod;
|
||||
private String currentClass;
|
||||
private String currentFileName;
|
||||
private int currentClassMetadata = -1;
|
||||
private List<ClassMetadata> classesMetadata = new ArrayList<>();
|
||||
private int currentLine;
|
||||
|
||||
public LocationProvider getLocationProvider() {
|
||||
|
@ -96,18 +99,32 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
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() {
|
||||
if (debugInformation == null) {
|
||||
debugInformation = new DebugInformation();
|
||||
|
||||
debugInformation.fileNames = files.getItems();
|
||||
debugInformation.fileNameMap = files.getIndexes();
|
||||
debugInformation.fileNames = files.getItems();;
|
||||
debugInformation.classNames = classes.getItems();
|
||||
debugInformation.classNameMap = classes.getIndexes();
|
||||
debugInformation.fields = fields.getItems();
|
||||
debugInformation.methods = methods.getItems();
|
||||
debugInformation.methodMap = methods.getIndexes();
|
||||
debugInformation.variableNames = variableNames.getItems();
|
||||
debugInformation.variableNameMap = variableNames.getIndexes();
|
||||
|
||||
debugInformation.fileMapping = fileMapping.build();
|
||||
debugInformation.lineMapping = lineMapping.build();
|
||||
|
@ -119,7 +136,19 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
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.rebuildMaps();
|
||||
}
|
||||
return debugInformation;
|
||||
}
|
||||
|
@ -172,4 +201,8 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
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 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.IOException;
|
||||
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();
|
||||
debugInfo.fileNames = readStrings();
|
||||
debugInfo.classNames = readStrings();
|
||||
debugInfo.fields = readStrings();
|
||||
debugInfo.methods = readStrings();
|
||||
debugInfo.variableNames = readStrings();
|
||||
debugInfo.fileMapping = readMapping();
|
||||
|
@ -42,6 +47,7 @@ class DebugInformationReader {
|
|||
debugInfo.classMapping = readMapping();
|
||||
debugInfo.methodMapping = readMapping();
|
||||
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
|
||||
debugInfo.classesMetadata = readClassesMetadata(debugInfo.classNames.length);
|
||||
debugInfo.rebuildFileDescriptions();
|
||||
debugInfo.rebuildMaps();
|
||||
return debugInfo;
|
||||
|
@ -58,6 +64,22 @@ class DebugInformationReader {
|
|||
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) {
|
||||
boolean negative = (number & 1) != 0;
|
||||
number >>>= 1;
|
||||
|
|
|
@ -17,6 +17,10 @@ package org.teavm.debugging;
|
|||
|
||||
import java.io.DataOutput;
|
||||
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 {
|
||||
writeStringArray(debugInfo.fileNames);
|
||||
writeStringArray(debugInfo.classNames);
|
||||
writeStringArray(debugInfo.fields);
|
||||
writeStringArray(debugInfo.methods);
|
||||
writeStringArray(debugInfo.variableNames);
|
||||
|
||||
|
@ -41,6 +46,7 @@ class DebugInformationWriter {
|
|||
writeMapping(debugInfo.classMapping);
|
||||
writeMapping(debugInfo.methodMapping);
|
||||
writeVariableMappings(debugInfo);
|
||||
writeClassMetadata(debugInfo.classesMetadata);
|
||||
}
|
||||
|
||||
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) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
|
||||
|
|
|
@ -288,6 +288,16 @@ public class Debugger {
|
|||
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() {
|
||||
@Override
|
||||
public void resumed() {
|
||||
|
|
|
@ -43,4 +43,12 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
|||
@Override
|
||||
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 {
|
||||
String getRepresentation();
|
||||
|
||||
String getClassName();
|
||||
|
||||
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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public abstract class Value {
|
||||
public abstract String getRepresentation();
|
||||
public class Value {
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
SimpleValue value = new SimpleValue(jsVar.getValue().getRepresentation());
|
||||
Value value = new Value(debugger, jsVar.getValue());
|
||||
vars.put(entry.getKey(), new Variable(name, value));
|
||||
}
|
||||
backingMap.compareAndSet(null, vars);
|
||||
|
|
|
@ -243,6 +243,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
public void render(ClassNode cls) throws RenderingException {
|
||||
debugEmitter.emitClass(cls.getName());
|
||||
debugEmitter.addClass(cls.getName());
|
||||
try {
|
||||
writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{")
|
||||
.indent().softNewLine();
|
||||
|
@ -254,8 +255,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
if (value == null) {
|
||||
value = getDefaultValue(field.getType());
|
||||
}
|
||||
writer.append("this.").appendField(new FieldReference(cls.getName(), field.getName())).ws()
|
||||
.append("=").ws().append(constantToString(value)).append(";").softNewLine();
|
||||
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
|
||||
writer.append("this.").appendField(fieldRef).ws().append("=").ws().append(constantToString(value))
|
||||
.append(";").softNewLine();
|
||||
debugEmitter.addField(field.getName(), naming.getNameFor(fieldRef));
|
||||
}
|
||||
writer.outdent().append("}").newLine();
|
||||
|
||||
|
@ -267,8 +270,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
if (value == null) {
|
||||
value = getDefaultValue(field.getType());
|
||||
}
|
||||
writer.appendClass(cls.getName()).append('.')
|
||||
.appendField(new FieldReference(cls.getName(), field.getName())).ws().append("=").ws()
|
||||
FieldReference fieldRef = new FieldReference(cls.getName(), field.getName());
|
||||
writer.appendClass(cls.getName()).append('.').appendField(fieldRef).ws().append("=").ws()
|
||||
.append(constantToString(value)).append(";").softNewLine();
|
||||
}
|
||||
|
||||
|
|
|
@ -398,7 +398,8 @@ function $dbg_class(obj) {
|
|||
if (obj instanceof Long) {
|
||||
return "long";
|
||||
}
|
||||
return obj.constructor.$meta.name;
|
||||
var meta = obj.constructor.$meta;
|
||||
return meta ? meta.name : "";
|
||||
}
|
||||
|
||||
Long = function(lo, hi) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user