diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java index d41c827b0..54d69c634 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java @@ -4,9 +4,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Exchanger; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; @@ -277,26 +275,47 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC params.setObjectId(scopeId); params.setOwnProperties(true); message.setParams(mapper.valueToTree(params)); - final Exchanger> exchanger = new Exchanger<>(); + final BlockingQueue> sync = new LinkedTransferQueue<>(); responseHandlers.put(message.getId(), new ResponseHandler() { @Override public void received(JsonNode node) throws IOException { GetPropertiesResponse response = mapper.reader(GetPropertiesResponse.class).readValue(node); - // TODO: parse response - try { - exchanger.exchange(new ArrayList()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + sync.add(parseProperties(response.getResult())); } }); sendMessage(message); try { - return exchanger.exchange(null); + return sync.take(); } catch (InterruptedException e) { return Collections.emptyList(); } } + private List parseProperties(PropertyDescriptorDTO[] properties) { + List variables = new ArrayList<>(); + if (properties != null) { + for (PropertyDescriptorDTO property : properties) { + RemoteObjectDTO remoteValue = property.getValue(); + RDPValue value; + switch (remoteValue.getType()) { + case "undefined": + value = new RDPValue("undefined"); + break; + case "object": + case "function": + value = new RDPValue(remoteValue.getObjectId()); + break; + default: + value = new RDPValue(remoteValue.getValue().asText()); + break; + } + + RDPLocalVariable var = new RDPLocalVariable(property.getName(), value); + variables.add(var); + } + } + return variables; + } + private T parseJson(Class type, JsonNode node) throws IOException { return mapper.reader(type).readValue(node); } @@ -316,7 +335,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC String scopeId = null; for (ScopeDTO scope : dto.getScopeChain()) { if (scope.getType().equals("local")) { - scopeId = scope.getObject(); + scopeId = scope.getObject().getObjectId(); break; } } diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/ScopeDTO.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/ScopeDTO.java index fda09c677..7bb6e3e2d 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/ScopeDTO.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/data/ScopeDTO.java @@ -8,14 +8,14 @@ import org.codehaus.jackson.annotate.JsonIgnoreProperties; */ @JsonIgnoreProperties(ignoreUnknown = true) public class ScopeDTO { - private String object; + private RemoteObjectDTO object; private String type; - public String getObject() { + public RemoteObjectDTO getObject() { return object; } - public void setObject(String object) { + public void setObject(RemoteObjectDTO object) { this.object = object; } diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/messages/GetPropertiesResponse.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/messages/GetPropertiesResponse.java index 509cc4324..6c8e3be9a 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/messages/GetPropertiesResponse.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/messages/GetPropertiesResponse.java @@ -9,13 +9,13 @@ import org.teavm.chromerdp.data.PropertyDescriptorDTO; */ @JsonIgnoreProperties(ignoreUnknown = true) public class GetPropertiesResponse { - private PropertyDescriptorDTO[] properties; + private PropertyDescriptorDTO[] result; - public PropertyDescriptorDTO[] getProperties() { - return properties; + public PropertyDescriptorDTO[] getResult() { + return result; } - public void setProperties(PropertyDescriptorDTO[] properties) { - this.properties = properties; + public void setResult(PropertyDescriptorDTO[] properties) { + this.result = properties; } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/CallFrame.java b/teavm-core/src/main/java/org/teavm/debugging/CallFrame.java index 80a51b764..5fdc7a473 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/CallFrame.java +++ b/teavm-core/src/main/java/org/teavm/debugging/CallFrame.java @@ -26,9 +26,9 @@ import org.teavm.model.MethodReference; public class CallFrame { private SourceLocation location; private MethodReference method; - private Map variables; + private Map variables; - CallFrame(SourceLocation location, MethodReference method, Map variables) { + CallFrame(SourceLocation location, MethodReference method, Map variables) { this.location = location; this.method = method; this.variables = Collections.unmodifiableMap(variables); @@ -42,7 +42,7 @@ public class CallFrame { return method; } - public Map getVariables() { + public Map getVariables() { return variables; } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java index d37249026..649189794 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java @@ -50,12 +50,10 @@ class DebugInformationReader { private DebugInformation.Mapping[] readVariableMappings(int count) throws IOException { DebugInformation.Mapping[] mappings = new DebugInformation.Mapping[count]; int varCount = readUnsignedNumber(); + int lastVar = 0; while (varCount-- > 0) { - int lastVar = 0; - for (int i = 0; i < mappings.length; ++i) { - lastVar += readUnsignedNumber(); - mappings[lastVar] = readMapping(); - } + lastVar += readUnsignedNumber(); + mappings[lastVar] = readMapping(); } return mappings; } diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java index d1402c39d..c876ff0ad 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java @@ -40,12 +40,12 @@ class DebugInformationWriter { writeMapping(debugInfo.lineMapping); writeMapping(debugInfo.classMapping); writeMapping(debugInfo.methodMapping); - writeUnsignedNumber(nonNullVariableMappings(debugInfo)); writeVariableMappings(debugInfo); } private void writeVariableMappings(DebugInformation debugInfo) throws IOException { int lastVar = 0; + writeUnsignedNumber(nonNullVariableMappings(debugInfo)); for (int i = 0; i < debugInfo.variableMappings.length; ++i) { DebugInformation.Mapping mapping = debugInfo.variableMappings[i]; if (mapping == null) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java index eabab3b1b..c944f6c22 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -186,7 +186,8 @@ public class Debugger { MethodReference method = !empty ? debugInformation.getMethodAt(jsFrame.getLocation().getLine(), jsFrame.getLocation().getColumn()) : null; if (!empty || !wasEmpty) { - frames.add(new CallFrame(loc, method, new HashMap())); + VariableMap vars = new VariableMap(jsFrame.getVariables(), this, jsFrame.getLocation()); + frames.add(new CallFrame(loc, method, vars)); } wasEmpty = empty; } @@ -279,6 +280,14 @@ public class Debugger { } } + public String mapVariable(String variable, JavaScriptLocation location) { + DebugInformation debugInfo = debugInformationMap.get(location.getScript()); + if (debugInfo == null) { + return null; + } + return debugInfo.getVariableMeaningAt(location.getLine(), location.getColumn(), variable); + } + private JavaScriptDebuggerListener javaScriptListener = new JavaScriptDebuggerListener() { @Override public void resumed() { diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptValue.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptValue.java index 7541f781b..e23989495 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptValue.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptValue.java @@ -1,3 +1,18 @@ +/* + * 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.Map; diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptVariable.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptVariable.java index 511216f39..ff33c83c1 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptVariable.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptVariable.java @@ -1,3 +1,18 @@ +/* + * 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; /** diff --git a/teavm-core/src/main/java/org/teavm/debugging/LocalVariable.java b/teavm-core/src/main/java/org/teavm/debugging/LocalVariable.java deleted file mode 100644 index e98029b55..000000000 --- a/teavm-core/src/main/java/org/teavm/debugging/LocalVariable.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.teavm.debugging; - -/** - * - * @author Alexey Andreev - */ -public class LocalVariable { - private String name; - private WatchedValue value; - - LocalVariable(String name, WatchedValue value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public WatchedValue getValue() { - return value; - } -} diff --git a/teavm-core/src/main/java/org/teavm/debugging/SimpleValue.java b/teavm-core/src/main/java/org/teavm/debugging/SimpleValue.java new file mode 100644 index 000000000..e977361ee --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/SimpleValue.java @@ -0,0 +1,41 @@ +/* + * 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 getProperties() { + return Collections.emptyMap(); + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/Value.java b/teavm-core/src/main/java/org/teavm/debugging/Value.java new file mode 100644 index 000000000..3a768a141 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/Value.java @@ -0,0 +1,28 @@ +/* + * 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.Map; + +/** + * + * @author Alexey Andreev + */ +public abstract class Value { + public abstract String getRepresentation(); + + public abstract Map getProperties(); +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/Variable.java b/teavm-core/src/main/java/org/teavm/debugging/Variable.java new file mode 100644 index 000000000..1bb2bcab5 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/Variable.java @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * + * @author Alexey Andreev + */ +public class Variable { + private String name; + private Value value; + + Variable(String name, Value value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public Value getValue() { + return value; + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java b/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java new file mode 100644 index 000000000..cc53aa26e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java @@ -0,0 +1,74 @@ +/* + * 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.AbstractMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +/** + * + * @author Alexey Andreev + */ +class VariableMap extends AbstractMap { + private AtomicReference> backingMap = new AtomicReference<>(); + private Map jsVariables; + private Debugger debugger; + private JavaScriptLocation location; + + public VariableMap(Map jsVariables, Debugger debugger, JavaScriptLocation location) { + this.jsVariables = jsVariables; + this.debugger = debugger; + this.location = location; + } + + @Override + public Set> entrySet() { + updateBackingMap(); + return backingMap.get().entrySet(); + } + + @Override + public Variable get(Object key) { + updateBackingMap(); + return backingMap.get().get(key); + } + + @Override + public int size() { + updateBackingMap(); + return backingMap.get().size(); + } + + private void updateBackingMap() { + if (backingMap.get() != null) { + return; + } + Map vars = new HashMap<>(); + for (Map.Entry entry : jsVariables.entrySet()) { + JavaScriptVariable jsVar = entry.getValue(); + String name = debugger.mapVariable(entry.getKey(), location); + if (name == null) { + continue; + } + SimpleValue value = new SimpleValue(jsVar.getValue().getRepresentation()); + vars.put(entry.getKey(), new Variable(name, value)); + } + backingMap.compareAndSet(null, vars); + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/WatchedValue.java b/teavm-core/src/main/java/org/teavm/debugging/WatchedValue.java deleted file mode 100644 index bf44a8410..000000000 --- a/teavm-core/src/main/java/org/teavm/debugging/WatchedValue.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.teavm.debugging; - -import java.util.Map; - -/** - * - * @author Alexey Andreev - */ -public abstract class WatchedValue { - public abstract String getRepresentation(); - - public abstract Map getProperties(); -} diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index c18cb3fee..c6cad5fa5 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -119,13 +119,16 @@ public class ProgramParser implements VariableDebugInformation { while (program.variableCount() <= signatureVars) { program.createVariable(getVariableDebugName(program.variableCount(), 0)); } - for (int i = 0; i < signatureVars; ++i) { + for (int i = 0; i <= signatureVars; ++i) { parameterNames.put(i, getVariableDebugName(i, 0)); } return program; } private String getVariableDebugName(int var, int location) { + if (var < 0) { + return null; + } List nodes = localVariableMap.get(var); if (nodes == null) { return null; @@ -293,10 +296,13 @@ public class ProgramParser implements VariableDebugInformation { DefinitionExtractor defExtractor = new DefinitionExtractor(); for (int i = 0; i < targetInstructions.size(); ++i) { List instructionList = targetInstructions.get(i); + if (instructionList == null) { + continue; + } for (Instruction insn : instructionList) { insn.acceptVisitor(defExtractor); for (Variable var : defExtractor.getDefinedVariables()) { - String debugName = getVariableDebugName(var.getIndex(), i); + String debugName = getVariableDebugName(var.getIndex() - minLocal, i); if (debugName != null) { variableDebugNames.put(insn, debugName); } diff --git a/teavm-core/src/main/java/org/teavm/parsing/VariableDebugInformation.java b/teavm-core/src/main/java/org/teavm/parsing/VariableDebugInformation.java index db11c723e..55fcda47a 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/VariableDebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/parsing/VariableDebugInformation.java @@ -1,3 +1,18 @@ +/* + * 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.parsing; import org.teavm.model.Instruction;