Fix calculating class name in debugger

This commit is contained in:
Alexey Andreev 2018-11-19 15:29:02 +03:00
parent f2dd398719
commit 0f951f8c86
12 changed files with 96 additions and 23 deletions

View File

@ -272,9 +272,10 @@ public class Renderer implements RenderingManager {
} }
private void renderDeclaration(ClassNode cls) throws RenderingException { private void renderDeclaration(ClassNode cls) throws RenderingException {
debugEmitter.addClass(cls.getName(), cls.getParentName()); String jsName = writer.getNaming().getNameFor(cls.getName());
debugEmitter.addClass(jsName, cls.getName(), cls.getParentName());
try { try {
writer.append("function ").appendClass(cls.getName()).append("()").ws().append("{") writer.append("function " + jsName + "()").ws().append("{")
.indent().softNewLine(); .indent().softNewLine();
boolean thisAliased = false; boolean thisAliased = false;
List<FieldNode> nonStaticFields = new ArrayList<>(); List<FieldNode> nonStaticFields = new ArrayList<>();

View File

@ -302,7 +302,8 @@ public class Debugger {
MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(), MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(),
jsFrame.getLocation().getColumn()) : null; jsFrame.getLocation().getColumn()) : null;
if (!empty || !wasEmpty) { if (!empty || !wasEmpty) {
VariableMap vars = new VariableMap(jsFrame.getVariables(), this, jsFrame.getLocation()); VariableMap vars = new VariableMap(jsFrame.getVariables(), this, debugInformation,
jsFrame.getLocation());
frames.add(new CallFrame(this, jsFrame, loc, method, vars)); frames.add(new CallFrame(this, jsFrame, loc, method, vars));
} }
wasEmpty = empty; wasEmpty = empty;

View File

@ -19,6 +19,7 @@ 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; import java.util.concurrent.atomic.AtomicReference;
import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.javascript.JavaScriptVariable; import org.teavm.debugging.javascript.JavaScriptVariable;
class PropertyMap extends AbstractMap<String, Variable> { class PropertyMap extends AbstractMap<String, Variable> {
@ -26,11 +27,14 @@ class PropertyMap extends AbstractMap<String, Variable> {
private AtomicReference<Map<String, Variable>> backingMap = new AtomicReference<>(); private AtomicReference<Map<String, Variable>> backingMap = new AtomicReference<>();
private Map<String, JavaScriptVariable> jsVariables; private Map<String, JavaScriptVariable> jsVariables;
private Debugger debugger; private Debugger debugger;
private DebugInformation debugInformation;
public PropertyMap(String className, Map<String, JavaScriptVariable> jsVariables, Debugger debugger) { public PropertyMap(String className, Map<String, JavaScriptVariable> jsVariables, Debugger debugger,
DebugInformation debugInformation) {
this.className = className; this.className = className;
this.jsVariables = jsVariables; this.jsVariables = jsVariables;
this.debugger = debugger; this.debugger = debugger;
this.debugInformation = debugInformation;
} }
@Override @Override
@ -73,7 +77,7 @@ class PropertyMap extends AbstractMap<String, Variable> {
continue; continue;
} }
} }
Value value = new Value(debugger, jsVar.getValue()); Value value = new Value(debugger, debugInformation, jsVar.getValue());
vars.put(name, new Variable(name, value)); vars.put(name, new Variable(name, value));
} }
backingMap.compareAndSet(null, vars); backingMap.compareAndSet(null, vars);

View File

@ -17,15 +17,18 @@ package org.teavm.debugging;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.javascript.JavaScriptValue; import org.teavm.debugging.javascript.JavaScriptValue;
public class Value { public class Value {
private Debugger debugger; private Debugger debugger;
private DebugInformation debugInformation;
private JavaScriptValue jsValue; private JavaScriptValue jsValue;
private AtomicReference<PropertyMap> properties = new AtomicReference<>(); private AtomicReference<PropertyMap> properties = new AtomicReference<>();
Value(Debugger debugger, JavaScriptValue jsValue) { Value(Debugger debugger, DebugInformation debugInformation, JavaScriptValue jsValue) {
this.debugger = debugger; this.debugger = debugger;
this.debugInformation = debugInformation;
this.jsValue = jsValue; this.jsValue = jsValue;
} }
@ -34,12 +37,23 @@ public class Value {
} }
public String getType() { public String getType() {
return jsValue.getClassName(); String className = jsValue.getClassName();
if (className.startsWith("a/")) {
className = className.substring(2);
String javaClassName = debugInformation.getClassNameByJsName(className);
if (javaClassName != null) {
className = javaClassName;
}
} else if (className.startsWith("@")) {
className = className.substring(1);
}
return className;
} }
public Map<String, Variable> getProperties() { public Map<String, Variable> getProperties() {
if (properties.get() == null) { if (properties.get() == null) {
properties.compareAndSet(null, new PropertyMap(jsValue.getClassName(), jsValue.getProperties(), debugger)); properties.compareAndSet(null, new PropertyMap(jsValue.getClassName(), jsValue.getProperties(), debugger,
debugInformation));
} }
return properties.get(); return properties.get();
} }

View File

@ -20,6 +20,7 @@ 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; import java.util.concurrent.atomic.AtomicReference;
import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.javascript.JavaScriptLocation; import org.teavm.debugging.javascript.JavaScriptLocation;
import org.teavm.debugging.javascript.JavaScriptVariable; import org.teavm.debugging.javascript.JavaScriptVariable;
@ -27,11 +28,14 @@ class VariableMap extends AbstractMap<String, Variable> {
private AtomicReference<Map<String, Variable>> backingMap = new AtomicReference<>(); private AtomicReference<Map<String, Variable>> backingMap = new AtomicReference<>();
private Map<String, JavaScriptVariable> jsVariables; private Map<String, JavaScriptVariable> jsVariables;
private Debugger debugger; private Debugger debugger;
private DebugInformation debugInformation;
private JavaScriptLocation location; private JavaScriptLocation location;
public VariableMap(Map<String, JavaScriptVariable> jsVariables, Debugger debugger, JavaScriptLocation location) { public VariableMap(Map<String, JavaScriptVariable> jsVariables, Debugger debugger,
DebugInformation debugInformation, JavaScriptLocation location) {
this.jsVariables = jsVariables; this.jsVariables = jsVariables;
this.debugger = debugger; this.debugger = debugger;
this.debugInformation = debugInformation;
this.location = location; this.location = location;
} }
@ -61,7 +65,7 @@ class VariableMap extends AbstractMap<String, Variable> {
for (Map.Entry<String, JavaScriptVariable> entry : jsVariables.entrySet()) { for (Map.Entry<String, JavaScriptVariable> entry : jsVariables.entrySet()) {
JavaScriptVariable jsVar = entry.getValue(); JavaScriptVariable jsVar = entry.getValue();
String[] names = debugger.mapVariable(entry.getKey(), location); String[] names = debugger.mapVariable(entry.getKey(), location);
Value value = new Value(debugger, jsVar.getValue()); Value value = new Value(debugger, debugInformation, jsVar.getValue());
for (String name : names) { for (String name : names) {
if (name == null) { if (name == null) {
name = "js:" + jsVar.getName(); name = "js:" + jsVar.getName();

View File

@ -47,6 +47,7 @@ public class DebugInformation {
RecordArray[] lineCallSites; RecordArray[] lineCallSites;
RecordArray[] controlFlowGraphs; RecordArray[] controlFlowGraphs;
List<ClassMetadata> classesMetadata; List<ClassMetadata> classesMetadata;
Map<String, ClassMetadata> classMetadataByJsName;
RecordArray methodEntrances; RecordArray methodEntrances;
MethodTree methodTree; MethodTree methodTree;
@ -270,6 +271,11 @@ public class DebugInformation {
return null; return null;
} }
public String getClassNameByJsName(String className) {
ClassMetadata cls = classMetadataByJsName.get(className);
return cls != null ? classNames[cls.id] : null;
}
public DebuggerCallSite getCallSite(GeneratedLocation location) { public DebuggerCallSite getCallSite(GeneratedLocation location) {
int keyIndex = indexByKey(callSiteMapping, location); int keyIndex = indexByKey(callSiteMapping, location);
return keyIndex >= 0 ? getCallSite(keyIndex) : null; return keyIndex >= 0 ? getCallSite(keyIndex) : null;
@ -411,6 +417,7 @@ public class DebugInformation {
rebuildEntrances(); rebuildEntrances();
rebuildMethodTree(); rebuildMethodTree();
rebuildLineCallSites(); rebuildLineCallSites();
rebuildClassMap();
} }
void rebuildMaps() { void rebuildMaps() {
@ -594,6 +601,15 @@ public class DebugInformation {
return new GeneratedLocation(record.get(0), record.get(1)); return new GeneratedLocation(record.get(0), record.get(1));
} }
private void rebuildClassMap() {
classMetadataByJsName = new HashMap<>();
for (DebugInformation.ClassMetadata cls : classesMetadata) {
if (cls.jsName != null) {
classMetadataByJsName.put(cls.jsName, cls);
}
}
}
private int binarySearchLocation(RecordArray array, int row, int column) { private int binarySearchLocation(RecordArray array, int row, int column) {
int l = 0; int l = 0;
int u = array.size() - 1; int u = array.size() - 1;
@ -640,9 +656,11 @@ public class DebugInformation {
} }
static class ClassMetadata { static class ClassMetadata {
int id;
Integer parentId; Integer parentId;
Map<Integer, Integer> fieldMap = new HashMap<>(); Map<Integer, Integer> fieldMap = new HashMap<>();
int[] methods; int[] methods;
String jsName;
} }
class MethodTree { class MethodTree {

View File

@ -177,14 +177,17 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
} }
@Override @Override
public void addClass(String className, String parentName) { public void addClass(String jsName, String className, String parentName) {
int classIndex = classes.index(className); int classIndex = classes.index(className);
int parentIndex = classes.index(parentName); int parentIndex = classes.index(parentName);
while (classIndex >= classesMetadata.size()) { while (classIndex >= classesMetadata.size()) {
classesMetadata.add(new ClassMetadata()); classesMetadata.add(new ClassMetadata());
} }
currentClassMetadata = classIndex; currentClassMetadata = classIndex;
classesMetadata.get(currentClassMetadata).parentIndex = parentIndex;
ClassMetadata metadata = classesMetadata.get(classIndex);
metadata.parentIndex = parentIndex;
metadata.jsName = jsName;
} }
@Override @Override
@ -288,15 +291,15 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
List<DebugInformation.ClassMetadata> builtMetadata = new ArrayList<>(classes.list.size()); List<DebugInformation.ClassMetadata> builtMetadata = new ArrayList<>(classes.list.size());
for (int i = 0; i < classes.list.size(); ++i) { for (int i = 0; i < classes.list.size(); ++i) {
if (i >= classesMetadata.size()) {
builtMetadata.add(new DebugInformation.ClassMetadata());
} else {
ClassMetadata origMetadata = classesMetadata.get(i);
DebugInformation.ClassMetadata mappedMetadata = new DebugInformation.ClassMetadata(); DebugInformation.ClassMetadata mappedMetadata = new DebugInformation.ClassMetadata();
mappedMetadata.id = i;
if (i < classesMetadata.size()) {
ClassMetadata origMetadata = classesMetadata.get(i);
mappedMetadata.jsName = origMetadata.jsName;
mappedMetadata.fieldMap.putAll(origMetadata.fieldMap); mappedMetadata.fieldMap.putAll(origMetadata.fieldMap);
mappedMetadata.parentId = origMetadata.parentIndex >= 0 ? origMetadata.parentIndex : null; mappedMetadata.parentId = origMetadata.parentIndex >= 0 ? origMetadata.parentIndex : null;
builtMetadata.add(mappedMetadata);
} }
builtMetadata.add(mappedMetadata);
} }
debugInformation.classesMetadata = builtMetadata; debugInformation.classesMetadata = builtMetadata;
@ -340,6 +343,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
static class ClassMetadata { static class ClassMetadata {
int parentIndex; int parentIndex;
String jsName;
Map<Integer, Integer> fieldMap = new HashMap<>(); Map<Integer, Integer> fieldMap = new HashMap<>();
} }
} }

View File

@ -33,7 +33,7 @@ public interface DebugInformationEmitter {
DeferredCallSite emitCallSite(); DeferredCallSite emitCallSite();
void addClass(String className, String parentName); void addClass(String jsName, String className, String parentName);
void addField(String fieldName, String jsName); void addField(String fieldName, String jsName);

View File

@ -18,6 +18,7 @@ package org.teavm.debugging.information;
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.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.teavm.common.RecordArray; import org.teavm.common.RecordArray;
@ -68,6 +69,8 @@ class DebugInformationReader {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
DebugInformation.ClassMetadata cls = new DebugInformation.ClassMetadata(); DebugInformation.ClassMetadata cls = new DebugInformation.ClassMetadata();
classes.add(cls); classes.add(cls);
cls.id = i;
cls.jsName = readNullableString();
cls.parentId = readUnsignedNumber() - 1; cls.parentId = readUnsignedNumber() - 1;
if (cls.parentId.equals(-1)) { if (cls.parentId.equals(-1)) {
cls.parentId = null; cls.parentId = null;
@ -322,7 +325,16 @@ class DebugInformationReader {
} }
private String readString() throws IOException { private String readString() throws IOException {
byte[] bytes = new byte[readUnsignedNumber()]; return readStringChars(readUnsignedNumber());
}
private String readNullableString() throws IOException {
int size = readUnsignedNumber();
return size > 0 ? readStringChars(size - 1) : null;
}
private String readStringChars(int size) throws IOException {
byte[] bytes = new byte[size];
int pos = 0; int pos = 0;
while (pos < bytes.length) { while (pos < bytes.length) {
int read = input.read(bytes, pos, bytes.length - pos); int read = input.read(bytes, pos, bytes.length - pos);
@ -331,6 +343,6 @@ class DebugInformationReader {
} }
pos += read; pos += read;
} }
return new String(bytes, "UTF-8"); return new String(bytes, StandardCharsets.UTF_8);
} }
} }

View File

@ -17,6 +17,7 @@ package org.teavm.debugging.information;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -69,6 +70,7 @@ class DebugInformationWriter {
private void writeClassMetadata(List<ClassMetadata> classes) throws IOException { private void writeClassMetadata(List<ClassMetadata> classes) throws IOException {
for (int i = 0; i < classes.size(); ++i) { for (int i = 0; i < classes.size(); ++i) {
ClassMetadata cls = classes.get(i); ClassMetadata cls = classes.get(i);
writeNullableString(cls.jsName);
writeUnsignedNumber(cls.parentId != null ? cls.parentId + 1 : 0); writeUnsignedNumber(cls.parentId != null ? cls.parentId + 1 : 0);
writeUnsignedNumber(cls.fieldMap.size()); writeUnsignedNumber(cls.fieldMap.size());
List<Integer> keys = new ArrayList<>(cls.fieldMap.keySet()); List<Integer> keys = new ArrayList<>(cls.fieldMap.keySet());
@ -295,8 +297,18 @@ class DebugInformationWriter {
} }
private void writeString(String str) throws IOException { private void writeString(String str) throws IOException {
byte[] bytes = str.getBytes("UTF-8"); byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
writeUnsignedNumber(bytes.length); writeUnsignedNumber(bytes.length);
output.write(bytes); output.write(bytes);
} }
private void writeNullableString(String str) throws IOException {
if (str == null) {
writeUnsignedNumber(0);
return;
}
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
writeUnsignedNumber(bytes.length + 1);
output.write(bytes);
}
} }

View File

@ -54,7 +54,7 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
} }
@Override @Override
public void addClass(String className, String parentName) { public void addClass(String jsName, String className, String parentName) {
} }
@Override @Override

View File

@ -204,6 +204,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
if (scripts.putIfAbsent(params.getScriptId(), params.getUrl()) != null) { if (scripts.putIfAbsent(params.getScriptId(), params.getUrl()) != null) {
return; return;
} }
if (params.getUrl().equals("file://fake")) {
return;
}
scriptIds.put(params.getUrl(), params.getScriptId()); scriptIds.put(params.getUrl(), params.getScriptId());
for (JavaScriptDebuggerListener listener : getListeners()) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.scriptAdded(params.getUrl()); listener.scriptAdded(params.getUrl());
@ -355,7 +358,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
breakpoint.updating.set(true); breakpoint.updating.set(true);
try { try {
SetBreakpointResponse response = callMethod("Debugger.setBreakpoint", SetBreakpointResponse.class, params); SetBreakpointResponse response = callMethod("Debugger.setBreakpoint", SetBreakpointResponse.class, params);
if (response == null) { if (response != null) {
breakpoint.chromeId = response.getBreakpointId(); breakpoint.chromeId = response.getBreakpointId();
if (breakpoint.chromeId != null) { if (breakpoint.chromeId != null) {
breakpointsByChromeId.put(breakpoint.chromeId, breakpoint); breakpointsByChromeId.put(breakpoint.chromeId, breakpoint);