diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java index f2bc94084..def1bef59 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java @@ -33,8 +33,8 @@ public class JavacSupport implements ClassHolderTransformer { ValueType.object("javax.tools.JavaCompiler"))); Program program = new Program(); BasicBlock block = program.createBasicBlock(); - program.createVariable(null); - Variable var = program.createVariable(null); + program.createVariable(); + Variable var = program.createVariable(); ConstructInstruction construct = new ConstructInstruction(); construct.setReceiver(var); construct.setType("com.sun.tools.javac.api.JavacTool"); diff --git a/teavm-core/src/main/java/org/teavm/common/IntegerArray.java b/teavm-core/src/main/java/org/teavm/common/IntegerArray.java index 0425be4c9..4c128c38a 100644 --- a/teavm-core/src/main/java/org/teavm/common/IntegerArray.java +++ b/teavm-core/src/main/java/org/teavm/common/IntegerArray.java @@ -54,10 +54,13 @@ public class IntegerArray { return data[index]; } + public int[] getRange(int start, int end) { + return Arrays.copyOfRange(data, start, end); + } + public void set(int index, int value) { if (index >= sz) { - throw new IndexOutOfBoundsException("Index " + index + - " is greater than the list size " + sz); + throw new IndexOutOfBoundsException("Index " + index + " is greater than the list size " + sz); } data[index] = value; } @@ -90,6 +93,15 @@ public class IntegerArray { data[sz - 1] = item; } + public void remove(int index) { + remove(index, 1); + } + + public void remove(int index, int count) { + System.arraycopy(data, index + count, data, index, sz - index - count); + sz -= count; + } + public boolean contains(int item) { for (int i = 0; i < sz; ++i) { if (data[i] == item) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java index cf953196f..c628fc071 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -44,7 +44,7 @@ public class DebugInformation { Mapping classMapping; Mapping methodMapping; Mapping lineMapping; - Mapping[] variableMappings; + MultiMapping[] variableMappings; List> classesMetadata; public String[] getCoveredSourceFiles() { @@ -105,18 +105,18 @@ public class DebugInformation { return getMethodAt(new GeneratedLocation(line, column)); } - public String getVariableMeaningAt(int line, int column, String variable) { + public String[] getVariableMeaningAt(int line, int column, String variable) { return getVariableMeaningAt(new GeneratedLocation(line, column), variable); } - public String getVariableMeaningAt(GeneratedLocation location, String variable) { + public String[] getVariableMeaningAt(GeneratedLocation location, String variable) { Integer varIndex = variableNameMap.get(variable); if (varIndex == null) { - return null; + return new String[0]; } - Mapping mapping = variableMappings[varIndex]; + MultiMapping mapping = variableMappings[varIndex]; if (mapping == null) { - return null; + return new String[0]; } return componentByKey(mapping, variableNames, location); } @@ -140,11 +140,30 @@ public class DebugInformation { return valueIndex >= 0 ? values[valueIndex] : null; } + private String[] componentByKey(MultiMapping mapping, String[] values, GeneratedLocation location) { + int keyIndex = indexByKey(mapping, location); + if (keyIndex < 0) { + return new String[0]; + } + int start = mapping.offsets[keyIndex]; + int end = mapping.offsets[keyIndex + 1]; + String[] result = new String[end - start]; + for (int i = 0; i < result.length; ++i) { + result[i] = values[mapping.data[i + start]]; + } + return result; + } + private int indexByKey(Mapping mapping, GeneratedLocation location) { int index = Collections.binarySearch(mapping.keyList(), location); return index >= 0 ? index : -index - 2; } + private int indexByKey(MultiMapping mapping, GeneratedLocation location) { + int index = Collections.binarySearch(mapping.keyList(), location); + return index >= 0 ? index : -index - 2; + } + public void write(OutputStream output) throws IOException { DebugInformationWriter writer = new DebugInformationWriter(new DataOutputStream(output)); writer.write(this); @@ -308,6 +327,32 @@ public class DebugInformation { } } + static class MultiMapping { + int[] lines; + int[] columns; + int[] offsets; + int[] data; + + public MultiMapping(int[] lines, int[] columns, int[] offsets, int[] data) { + this.lines = lines; + this.columns = columns; + this.offsets = offsets; + this.data = data; + } + + public LocationList keyList() { + return new LocationList(lines, columns); + } + + public int size() { + return lines.length; + } + + public GeneratedLocation key(int index) { + return new GeneratedLocation(lines[index], columns[index]); + } + } + static class LocationList extends AbstractList { private int[] lines; private int[] columns; diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java index a44f62b76..964ba4cb8 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java @@ -36,7 +36,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter { private Mapping lineMapping = new Mapping(); private Mapping classMapping = new Mapping(); private Mapping methodMapping = new Mapping(); - private Map variableMappings = new HashMap<>(); + private Map variableMappings = new HashMap<>(); private MethodDescriptor currentMethod; private String currentClass; private String currentFileName; @@ -88,15 +88,19 @@ public class DebugInformationBuilder implements DebugInformationEmitter { } @Override - public void emitVariable(String sourceName, String generatedName) { - int sourceIndex = variableNames.index(sourceName); + public void emitVariable(String[] sourceNames, String generatedName) { + int[] sourceIndexes = new int[sourceNames.length]; + for (int i = 0; i < sourceIndexes.length; ++i) { + sourceIndexes[i] = variableNames.index(sourceNames[i]); + } + Arrays.sort(sourceIndexes); int generatedIndex = variableNames.index(generatedName); - Mapping mapping = variableMappings.get(generatedIndex); + MultiMapping mapping = variableMappings.get(generatedIndex); if (mapping == null) { - mapping = new Mapping(); + mapping = new MultiMapping(); variableMappings.put(generatedIndex, mapping); } - mapping.add(locationProvider, sourceIndex); + mapping.add(locationProvider, sourceIndexes); } @Override @@ -130,9 +134,9 @@ public class DebugInformationBuilder implements DebugInformationEmitter { debugInformation.lineMapping = lineMapping.build(); debugInformation.classMapping = classMapping.build(); debugInformation.methodMapping = methodMapping.build(); - debugInformation.variableMappings = new DebugInformation.Mapping[variableNames.list.size()]; + debugInformation.variableMappings = new DebugInformation.MultiMapping[variableNames.list.size()]; for (int var : variableMappings.keySet()) { - Mapping mapping = variableMappings.get(var); + MultiMapping mapping = variableMappings.get(var); debugInformation.variableMappings[var] = mapping.build(); } @@ -163,6 +167,12 @@ public class DebugInformationBuilder implements DebugInformationEmitter { int last = lines.size() - 1; if (lines.get(last) == location.getLine() && columns.get(last) == location.getColumn()) { values.set(last, value); + // TODO: check why this gives an invalid result + /*if (values.get(last) == values.get(last - 1)) { + values.remove(last); + lines.remove(last); + columns.remove(last); + }*/ return; } } @@ -176,6 +186,78 @@ public class DebugInformationBuilder implements DebugInformationEmitter { } } + static class MultiMapping { + IntegerArray lines = new IntegerArray(1); + IntegerArray columns = new IntegerArray(1); + IntegerArray offsets = new IntegerArray(1); + IntegerArray data = new IntegerArray(1); + + public MultiMapping() { + offsets.add(0); + } + + public void add(LocationProvider location, int[] values) { + if (lines.size() > 1) { + int last = lines.size() - 1; + if (lines.get(last) == location.getLine() && columns.get(last) == location.getColumn()) { + addToLast(values); + return; + } + } + lines.add(location.getLine()); + columns.add(location.getColumn()); + data.addAll(values); + offsets.add(data.size()); + } + + private void addToLast(int[] values) { + int start = offsets.get(offsets.size() - 2); + int end = offsets.get(offsets.size() - 1); + int[] existing = data.getRange(start, end); + values = merge(existing, values); + if (values.length == existing.length) { + return; + } + data.remove(start, end - start); + data.addAll(values); + offsets.set(offsets.size() - 1, data.size()); + } + + private int[] merge(int[] a, int[] b) { + int[] result = new int[a.length + b.length]; + int i = 0; + int j = 0; + int k = 0; + while (i < a.length && j < b.length) { + int p = a[i]; + int q = b[j]; + if (p == q) { + result[k++] = p; + ++i; + ++j; + } else if (p < q) { + result[k++] = p; + ++i; + } else { + result[k++] = q; + ++j; + } + } + while (i < a.length) { + result[k++] = a[i++]; + } + while (j < b.length) { + result[k++] = b[j++]; + } + return k < result.length ? Arrays.copyOf(result, k) : result; + } + + public DebugInformation.MultiMapping build() { + return new DebugInformation.MultiMapping(lines.getAll(), columns.getAll(), offsets.getAll(), + data.getAll()); + } + } + static class MappedList { private List list = new ArrayList<>(); private Map map = new HashMap<>(); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java index b0a495d63..cf5e19276 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java @@ -31,7 +31,7 @@ public interface DebugInformationEmitter { void emitClass(String className); - void emitVariable(String sourceName, String generatedName); + void emitVariable(String[] sourceNames, String generatedName); void addClass(String className); 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 a5fc45ffd..3be13f8de 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java @@ -53,13 +53,13 @@ class DebugInformationReader { return debugInfo; } - private DebugInformation.Mapping[] readVariableMappings(int count) throws IOException { - DebugInformation.Mapping[] mappings = new DebugInformation.Mapping[count]; + private DebugInformation.MultiMapping[] readVariableMappings(int count) throws IOException { + DebugInformation.MultiMapping[] mappings = new DebugInformation.MultiMapping[count]; int varCount = readUnsignedNumber(); int lastVar = 0; while (varCount-- > 0) { lastVar += readUnsignedNumber(); - mappings[lastVar] = readMapping(); + mappings[lastVar] = readMultiMapping(); } return mappings; } @@ -86,6 +86,32 @@ class DebugInformationReader { return !negative ? number : -number; } + private DebugInformation.MultiMapping readMultiMapping() throws IOException { + int[] lines = readRle(); + int last = 0; + for (int i = 0; i < lines.length; ++i) { + last += lines[i]; + lines[i] = last; + } + int[] columns = new int[lines.length]; + resetRelativeNumber(); + for (int i = 0; i < columns.length; ++i) { + columns[i] = readRelativeNumber(); + } + int[] offsets = new int[lines.length + 1]; + int lastOffset = 0; + for (int i = 1; i < offsets.length; ++i) { + lastOffset += readUnsignedNumber(); + offsets[i] = lastOffset; + } + int[] data = new int[lastOffset]; + resetRelativeNumber(); + for (int i = 0; i < data.length; ++i) { + data[i] = readRelativeNumber(); + } + return new DebugInformation.MultiMapping(lines, columns, offsets, data); + } + private DebugInformation.Mapping readMapping() throws IOException { int[] lines = readRle(); int last = 0; 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 1d7e68a0c..7f6243b4e 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java @@ -53,7 +53,7 @@ class DebugInformationWriter { int lastVar = 0; writeUnsignedNumber(nonNullVariableMappings(debugInfo)); for (int i = 0; i < debugInfo.variableMappings.length; ++i) { - DebugInformation.Mapping mapping = debugInfo.variableMappings[i]; + DebugInformation.MultiMapping mapping = debugInfo.variableMappings[i]; if (mapping == null) { continue; } @@ -94,6 +94,30 @@ class DebugInformationWriter { } } + private void writeMapping(DebugInformation.MultiMapping mapping) throws IOException { + int[] lines = mapping.lines.clone(); + int last = 0; + for (int i = 0; i < lines.length; ++i) { + int next = lines[i]; + lines[i] -= last; + last = next; + } + writeRle(lines); + resetRelativeNumber(); + for (int i = 0; i < mapping.columns.length; ++i) { + writeRelativeNumber(mapping.columns[i]); + } + int lastOffset = 0; + for (int i = 1; i < mapping.offsets.length; ++i) { + writeUnsignedNumber(mapping.offsets[i] - lastOffset); + lastOffset = mapping.offsets[i]; + } + resetRelativeNumber(); + for (int i = 0; i < mapping.data.length; ++i) { + writeRelativeNumber(mapping.data[i]); + } + } + private void writeMapping(DebugInformation.Mapping mapping) throws IOException { int[] lines = mapping.lines.clone(); int last = 0; 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 1d42f6349..23f67a513 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -280,15 +280,15 @@ public class Debugger { } } - public String mapVariable(String variable, JavaScriptLocation location) { + String[] mapVariable(String variable, JavaScriptLocation location) { DebugInformation debugInfo = debugInformationMap.get(location.getScript()); if (debugInfo == null) { - return null; + return new String[0]; } return debugInfo.getVariableMeaningAt(location.getLine(), location.getColumn(), variable); } - public String mapField(String className, String jsField) { + String mapField(String className, String jsField) { for (DebugInformation debugInfo : debugInformationMap.values()) { String meaning = debugInfo.getFieldMeaning(className, jsField); if (meaning != null) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java index 9bef35c97..8754cfc9a 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java @@ -37,7 +37,7 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter { } @Override - public void emitVariable(String sourceName, String generatedName) { + public void emitVariable(String[] sourceName, String generatedName) { } @Override diff --git a/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java b/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java index cb5fb1ec5..85538d0cb 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java +++ b/teavm-core/src/main/java/org/teavm/debugging/VariableMap.java @@ -62,12 +62,11 @@ class VariableMap extends AbstractMap { 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; - } + String[] names = debugger.mapVariable(entry.getKey(), location); Value value = new Value(debugger, jsVar.getValue()); - vars.put(entry.getKey(), new Variable(name, value)); + for (String name : names) { + vars.put(name, new Variable(name, value)); + } } backingMap.compareAndSet(null, vars); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 74f104fc2..9b566be7c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -271,7 +271,7 @@ public class Decompiler { int paramCount = method.getSignature().length; for (int i = 0; i < paramCount; ++i) { Variable var = program.variableAt(i); - methodNode.getParameterDebugNames().add(var.getDebugName()); + methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames())); } return methodNode; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java b/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java index 59d872a8f..f915886d9 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java @@ -49,7 +49,7 @@ public class NullPointerExceptionTransformer implements ClassHolderTransformer { } NullCheckInstruction nullCheck = new NullCheckInstruction(); nullCheck.setValue(invoke.getInstance()); - Variable var = block.getProgram().createVariable(null); + Variable var = block.getProgram().createVariable(); nullCheck.setReceiver(var); invoke.setInstance(var); block.getInstructions().add(i++, nullCheck); diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index f976b318f..b897e1bfd 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -522,7 +522,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext try { MethodReference ref = method.getReference(); for (int i = 0; i < method.getParameterDebugNames().size(); ++i) { - debugEmitter.emitVariable(method.getParameterDebugNames().get(i), variableName(i)); + debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]), + variableName(i)); } int variableCount = 0; for (int var : method.getVariables()) { @@ -609,7 +610,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } if (statement.getLeftValue() instanceof VariableExpr) { VariableExpr receiver = (VariableExpr)statement.getLeftValue(); - debugEmitter.emitVariable(statement.getDebugName(), variableName(receiver.getIndex())); + debugEmitter.emitVariable(statement.getDebugNames().toArray(new String[0]), + variableName(receiver.getIndex())); } } catch (IOException e) { throw new RenderingException("IO error occured", e); diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java index 20444591f..4b69c3e52 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -244,7 +244,7 @@ class StatementGenerator implements InstructionVisitor { public void visit(AssignInstruction insn) { AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), Expr.var(insn.getAssignee().getIndex())); - stmt.setDebugName(insn.getReceiver().getDebugName()); + stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); stmt.setLocation(currentLocation); statements.add(stmt); } @@ -574,7 +574,7 @@ class StatementGenerator implements InstructionVisitor { private void assign(Expr source, Variable target) { AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source); stmt.setLocation(currentLocation); - stmt.setDebugName(target.getDebugName()); + stmt.getDebugNames().addAll(target.getDebugNames()); statements.add(stmt); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/AssignmentStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/AssignmentStatement.java index f76b6465e..8388d4a6c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/AssignmentStatement.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/AssignmentStatement.java @@ -15,6 +15,9 @@ */ package org.teavm.javascript.ast; +import java.util.HashSet; +import java.util.Set; + /** * * @author Alexey Andreev @@ -23,7 +26,7 @@ public class AssignmentStatement extends Statement { private Expr leftValue; private Expr rightValue; private NodeLocation location; - private String debugName; + private Set debugNames = new HashSet<>(); public Expr getLeftValue() { return leftValue; @@ -49,12 +52,8 @@ public class AssignmentStatement extends Statement { this.location = location; } - public String getDebugName() { - return debugName; - } - - public void setDebugName(String debugName) { - this.debugName = debugName; + public Set getDebugNames() { + return debugNames; } @Override diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java index f37a9ccb4..442d6a963 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java @@ -17,6 +17,7 @@ package org.teavm.javascript.ast; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.teavm.model.MethodReference; /** @@ -26,7 +27,7 @@ import org.teavm.model.MethodReference; public class RegularMethodNode extends MethodNode { private Statement body; private List variables = new ArrayList<>(); - private List parameterDebugNames = new ArrayList<>(); + private List> parameterDebugNames = new ArrayList<>(); public RegularMethodNode(MethodReference reference) { super(reference); @@ -44,7 +45,7 @@ public class RegularMethodNode extends MethodNode { return variables; } - public List getParameterDebugNames() { + public List> getParameterDebugNames() { return parameterDebugNames; } diff --git a/teavm-core/src/main/java/org/teavm/model/Program.java b/teavm-core/src/main/java/org/teavm/model/Program.java index ffb05aa15..9c3cab944 100644 --- a/teavm-core/src/main/java/org/teavm/model/Program.java +++ b/teavm-core/src/main/java/org/teavm/model/Program.java @@ -35,8 +35,8 @@ public class Program implements ProgramReader { return block; } - public Variable createVariable(String debugName) { - Variable variable = new Variable(this, debugName); + public Variable createVariable() { + Variable variable = new Variable(this); variable.setIndex(variables.size()); variables.add(variable); variable.setRegister(lastUsedRegister++); diff --git a/teavm-core/src/main/java/org/teavm/model/Variable.java b/teavm-core/src/main/java/org/teavm/model/Variable.java index 7f837516f..232cb200b 100644 --- a/teavm-core/src/main/java/org/teavm/model/Variable.java +++ b/teavm-core/src/main/java/org/teavm/model/Variable.java @@ -15,6 +15,10 @@ */ package org.teavm.model; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + /** * * @author Alexey Andreev @@ -23,11 +27,11 @@ public class Variable implements VariableReader { private Program program; private int index; private int register; - private String debugName; + private Set debugNames; - Variable(Program program, String debugName) { + Variable(Program program) { this.program = program; - this.debugName = debugName; + this.debugNames = new HashSet<>(); } @Override @@ -57,25 +61,12 @@ public class Variable implements VariableReader { this.register = register; } + public Set getDebugNames() { + return debugNames; + } + @Override - public String getDebugName() { - return debugName; - } - - public void setDebugName(String debugName) { - this.debugName = debugName; - } - - public void mergeDebugName(String otherDebugName) { - if (otherDebugName == null) { - return; - } - String[] parts = debugName != null ? debugName.split("\\|") : new String[0]; - for (String part : parts) { - if (otherDebugName.equals(part)) { - return; - } - } - debugName = debugName != null ? debugName + "|" + otherDebugName : otherDebugName; + public Set readDebugNames() { + return Collections.unmodifiableSet(debugNames); } } diff --git a/teavm-core/src/main/java/org/teavm/model/VariableReader.java b/teavm-core/src/main/java/org/teavm/model/VariableReader.java index a62aaa3d7..58637c520 100644 --- a/teavm-core/src/main/java/org/teavm/model/VariableReader.java +++ b/teavm-core/src/main/java/org/teavm/model/VariableReader.java @@ -15,6 +15,8 @@ */ package org.teavm.model; +import java.util.Set; + /** * * @author Alexey Andreev @@ -24,7 +26,7 @@ public interface VariableReader { ProgramReader getProgram(); - String getDebugName(); + Set readDebugNames(); int getRegister(); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java b/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java index 5e3de2eb7..d32a5e82a 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java @@ -29,8 +29,16 @@ public class ListingBuilder { for (int i = 0; i < program.variableCount(); ++i) { sb.append(prefix).append("var @").append(i); VariableReader var = program.variableAt(i); - if (var.getDebugName() != null) { - sb.append(" as ").append(var.getDebugName()); + if (!var.readDebugNames().isEmpty()) { + sb.append(" as "); + boolean first = true; + for (String debugName : var.readDebugNames()) { + if (!first) { + sb.append(", "); + } + first = false; + sb.append(debugName); + } } sb.append('\n'); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java index ec2bffac6..01b8de81e 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -73,7 +73,8 @@ public final class ProgramUtils { InstructionCopyReader insnCopier = new InstructionCopyReader(); insnCopier.programCopy = copy; for (int i = 0; i < program.variableCount(); ++i) { - copy.createVariable(program.variableAt(i).getDebugName()); + Variable var = copy.createVariable(); + var.getDebugNames().addAll(program.variableAt(i).readDebugNames()); } for (int i = 0; i < program.basicBlockCount(); ++i) { copy.createBasicBlock(); diff --git a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java index 34550c8c2..54f2497d6 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/teavm-core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -97,7 +97,7 @@ public class RegisterAllocator { final Phi phi = incoming.getPhi(); Program program = phi.getBasicBlock().getProgram(); AssignInstruction copyInstruction = new AssignInstruction(); - Variable firstCopy = program.createVariable(incoming.getValue().getDebugName()); + Variable firstCopy = program.createVariable(); copyInstruction.setReceiver(firstCopy); copyInstruction.setAssignee(incoming.getValue()); BasicBlock source = blockMap.get(incoming.getSource()); @@ -214,14 +214,14 @@ public class RegisterAllocator { varMap[tryCatch.getExceptionVariable().getIndex()])); } } - String[] originalNames = new String[program.variableCount()]; + String[][] originalNames = new String[program.variableCount()][]; for (int i = 0; i < program.variableCount(); ++i) { Variable var = program.variableAt(i); - originalNames[i] = var.getDebugName(); - var.setDebugName(null); + originalNames[i] = var.getDebugNames().toArray(new String[0]); + var.getDebugNames().clear(); } for (int i = 0; i < program.variableCount(); ++i) { - program.variableAt(varMap[i]).mergeDebugName(originalNames[i]); + program.variableAt(varMap[i]).getDebugNames().addAll(Arrays.asList(originalNames[i])); } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java index 429e52fb6..02334bf4f 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java +++ b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java @@ -114,7 +114,7 @@ public class GlobalValueNumbering implements MethodOptimization { if (map[i] != i) { Variable var = program.variableAt(i); Variable mapVar = program.variableAt(map[i]); - mapVar.mergeDebugName(var.getDebugName()); + mapVar.getDebugNames().addAll(var.getDebugNames()); program.deleteVariable(i); } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java index 4cc8c979e..74cf5a707 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java +++ b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java @@ -179,7 +179,7 @@ public class LoopInvariantMotion implements MethodOptimization { phi.getIncomings().remove(j--); if (preheaderPhi == null) { preheaderPhi = new Phi(); - preheaderPhi.setReceiver(program.createVariable(null)); + preheaderPhi.setReceiver(program.createVariable()); preheader.getPhis().add(preheaderPhi); } preheaderPhi.getIncomings().add(incoming); @@ -391,7 +391,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(ClassConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); ClassConstantInstruction copy = new ClassConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -400,7 +401,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(NullConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); NullConstantInstruction copy = new NullConstantInstruction(); copy.setReceiver(var); this.copy = copy; @@ -408,7 +410,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(IntegerConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); IntegerConstantInstruction copy = new IntegerConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -417,7 +420,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(LongConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); LongConstantInstruction copy = new LongConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -426,7 +430,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(FloatConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); FloatConstantInstruction copy = new FloatConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -435,7 +440,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(DoubleConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); DoubleConstantInstruction copy = new DoubleConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -444,7 +450,8 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(StringConstantInstruction insn) { - var = program.createVariable(insn.getReceiver().getDebugName()); + var = program.createVariable(); + var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); StringConstantInstruction copy = new StringConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); diff --git a/teavm-core/src/main/java/org/teavm/parsing/Parser.java b/teavm-core/src/main/java/org/teavm/parsing/Parser.java index e01940cda..f5b9c109a 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/Parser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/Parser.java @@ -44,7 +44,7 @@ public final class Parser { method.setProgram(program); parseAnnotations(method.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); while (program.variableCount() <= method.parameterCount()) { - program.createVariable(null); + program.createVariable(); } return method; } 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 5ef1bd86c..556046c9e 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -115,7 +115,7 @@ public class ProgramParser implements VariableDebugInformation { } int signatureVars = countSignatureVariables(method.desc); while (program.variableCount() <= signatureVars) { - program.createVariable(null); + program.createVariable(); } return program; } @@ -334,7 +334,7 @@ public class ProgramParser implements VariableDebugInformation { private Variable getVariable(int index) { while (index >= program.variableCount()) { - program.createVariable(null); + program.createVariable(); } return program.variableAt(index); } diff --git a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java index d713630b9..4e1c5ae78 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java @@ -140,17 +140,19 @@ public class SSATransformer { processed[currentBlock.getIndex()] = true; variableMap = Arrays.copyOf(task.variables, task.variables.length); for (Phi phi : currentBlock.getPhis()) { - Variable var = program.createVariable(phi.getReceiver().getDebugName()); + Variable var = program.createVariable(); + var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); variableMap[phi.getReceiver().getIndex()] = var; phi.setReceiver(var); } if (!caughtBlocks.get(currentBlock.getIndex()).isEmpty()) { Phi phi = new Phi(); - phi.setReceiver(program.createVariable(null)); + phi.setReceiver(program.createVariable()); for (TryCatchBlock tryCatch : caughtBlocks.get(currentBlock.getIndex())) { variableMap[tryCatch.getExceptionVariable().getIndex()] = phi.getReceiver(); - tryCatch.setExceptionVariable(program.createVariable( - tryCatch.getExceptionVariable().getDebugName())); + Set debugNames = tryCatch.getExceptionVariable().getDebugNames(); + tryCatch.setExceptionVariable(program.createVariable()); + tryCatch.getExceptionVariable().getDebugNames().addAll(debugNames); Incoming incoming = new Incoming(); incoming.setSource(tryCatch.getProtectedBlock()); incoming.setValue(tryCatch.getExceptionVariable()); @@ -182,7 +184,7 @@ public class SSATransformer { incoming.setSource(currentBlock); incoming.setValue(var); phi.getIncomings().add(incoming); - phi.getReceiver().mergeDebugName(var.getDebugName()); + phi.getReceiver().getDebugNames().addAll(var.getDebugNames()); } } } @@ -219,7 +221,7 @@ public class SSATransformer { } private Variable define(Variable var) { - Variable result = program.createVariable(null); + Variable result = program.createVariable(); variableMap[var.getIndex()] = result; return result; } @@ -231,7 +233,7 @@ public class SSATransformer { } String debugName = variableDebugMap.get(var.getIndex()); if (debugName != null) { - mappedVar.setDebugName(debugName); + mappedVar.getDebugNames().add(debugName); } return mappedVar; } diff --git a/teavm-eclipse-plugin/META-INF/MANIFEST.MF b/teavm-eclipse-plugin/META-INF/MANIFEST.MF index e6fd66cfa..ac305ad8c 100644 --- a/teavm-eclipse-plugin/META-INF/MANIFEST.MF +++ b/teavm-eclipse-plugin/META-INF/MANIFEST.MF @@ -5,18 +5,18 @@ Bundle-SymbolicName: teavm-eclipse-plugin;singleton:=true Bundle-Version: 0.2.0.qualifer Bundle-Vendor: Alexey Andreev Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Require-Bundle: org.eclipse.core.runtime;bundle-version="3.9.0", - org.eclipse.debug.core;bundle-version="3.8.0", - org.eclipse.debug.ui;bundle-version="3.9.0", - org.eclipse.swt;bundle-version="3.102.0", - org.eclipse.ui;bundle-version="3.105.0", - org.eclipse.jdt.debug;bundle-version="3.8.0", - org.eclipse.jdt.debug.ui;bundle-version="3.6.200", - org.eclipse.jdt.core;bundle-version="3.9.2", - org.eclipse.jdt.launching;bundle-version="3.7.1", - org.eclipse.ui.editors;bundle-version="3.8.100", - org.eclipse.ui.ide;bundle-version="3.9.0", - org.eclipse.jdt.ui;bundle-version="3.9.2" +Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.8.0,4.0)", + org.eclipse.debug.core;bundle-version="[3.7.0,4.0)", + org.eclipse.debug.ui;bundle-version="[3.8.0,4.0)", + org.eclipse.swt;bundle-version="[3.8.1,4.0)", + org.eclipse.ui;bundle-version="[3.7.1,4.0)", + org.eclipse.jdt.debug;bundle-version="[3.7.101,4.0.0)", + org.eclipse.jdt.debug.ui;bundle-version="[3.6.100,4.0.0)", + org.eclipse.jdt.core;bundle-version="[3.8.3,4.0.0)", + org.eclipse.jdt.launching;bundle-version="[3.6.1,4.0.0)", + org.eclipse.ui.editors;bundle-version="[3.8.0,4.0.0)", + org.eclipse.ui.ide;bundle-version="[3.8.2,4.0.0)", + org.eclipse.jdt.ui;bundle-version="[3.8.2,4.0.0)" Bundle-ClassPath: ., lib/asm-5.0.1.jar, lib/asm-commons-5.0.1.jar, diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java b/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java index 2c4557a3f..7a0cbd850 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java @@ -44,13 +44,13 @@ public class JCLHacks implements ClassHolderTransformer { MethodHolder method = new MethodHolder(desc); Program program = new Program(); for (int i = 0; i < desc.parameterCount(); ++i) { - program.createVariable(null); + program.createVariable(); } if (!staticMethod) { - program.createVariable(null); + program.createVariable(); } - program.createVariable(null); - Variable var = program.createVariable(null); + program.createVariable(); + Variable var = program.createVariable(); BasicBlock block = program.createBasicBlock(); ConstructInstruction cons = new ConstructInstruction(); cons.setType("java.lang.SecurityException"); @@ -75,8 +75,8 @@ public class JCLHacks implements ClassHolderTransformer { private MethodHolder createThreadSleep() { MethodHolder method = new MethodHolder("sleep", ValueType.LONG, ValueType.VOID); Program program = new Program(); - program.createVariable(null); - program.createVariable(null); + program.createVariable(); + program.createVariable(); BasicBlock block = program.createBasicBlock(); ExitInstruction exit = new ExitInstruction(); block.getInstructions().add(exit); diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java index 1f50781c6..73e6a0971 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java @@ -81,7 +81,7 @@ class JavascriptNativeProcessor { if (isProperGetter(method.getDescriptor())) { String propertyName = method.getName().charAt(0) == 'i' ? cutPrefix(method.getName(), 2) : cutPrefix(method.getName(), 3); - Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null; + Variable result = invoke.getReceiver() != null ? program.createVariable() : null; addPropertyGet(propertyName, invoke.getInstance(), result); if (result != null) { result = unwrap(result, method.getResultType()); @@ -96,7 +96,7 @@ class JavascriptNativeProcessor { } } else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) { if (isProperGetIndexer(method.getDescriptor())) { - Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null; + Variable result = invoke.getReceiver() != null ? program.createVariable() : null; addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0), method.parameterType(0)), result); if (result != null) { @@ -143,7 +143,7 @@ class JavascriptNativeProcessor { "a proper native JavaScript method or constructor declaration"); } } - Variable result = invoke.getReceiver() != null ? program.createVariable(null) : null; + Variable result = invoke.getReceiver() != null ? program.createVariable() : null; InvokeInstruction newInvoke = new InvokeInstruction(); ValueType[] signature = new ValueType[method.parameterCount() + 3]; Arrays.fill(signature, ValueType.object(JSObject.class.getName())); @@ -226,7 +226,7 @@ class JavascriptNativeProcessor { } private Variable addString(String str) { - Variable var = program.createVariable(null); + Variable var = program.createVariable(); StringConstantInstruction nameInsn = new StringConstantInstruction(); nameInsn.setReceiver(var); nameInsn.setConstant(str); @@ -261,7 +261,7 @@ class JavascriptNativeProcessor { } else if (className.equals("java.lang.String")) { return unwrap(var, "unwrapString", ValueType.object("java.lang.String")); } else { - Variable result = program.createVariable(null); + Variable result = program.createVariable(); CastInstruction castInsn = new CastInstruction(); castInsn.setReceiver(result); castInsn.setValue(var); @@ -274,7 +274,7 @@ class JavascriptNativeProcessor { } private Variable unwrap(Variable var, String methodName, ValueType resultType) { - Variable result = program.createVariable(null); + Variable result = program.createVariable(); InvokeInstruction insn = new InvokeInstruction(); insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.object(JSObject.class.getName()), resultType)); @@ -301,7 +301,7 @@ class JavascriptNativeProcessor { throw new RuntimeException("Wrong functor: " + type.getName()); } String name = type.getMethods().iterator().next().getName(); - Variable functor = program.createVariable(null); + Variable functor = program.createVariable(); Variable nameVar = addStringWrap(addString(name)); InvokeInstruction insn = new InvokeInstruction(); insn.setMethod(new MethodReference(JS.class.getName(), "function", @@ -321,7 +321,7 @@ class JavascriptNativeProcessor { return var; } } - Variable result = program.createVariable(null); + Variable result = program.createVariable(); InvokeInstruction insn = new InvokeInstruction(); insn.setMethod(new MethodReference(JS.class.getName(), "wrap", type, ValueType.object(JSObject.class.getName()))); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java index 42070e4a8..6d71fb628 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java @@ -131,7 +131,7 @@ class ResourceProgramTransformer { } else if (type instanceof ValueType.Object) { switch (((ValueType.Object)type).getClassName()) { case "java.lang.String": { - Variable resultVar = insn.getProgram().createVariable(null); + Variable resultVar = insn.getProgram().createVariable(); getProperty(insn, property, instructions, resultVar); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); @@ -143,7 +143,7 @@ class ResourceProgramTransformer { return instructions; } default: { - Variable resultVar = insn.getProgram().createVariable(null); + Variable resultVar = insn.getProgram().createVariable(); getProperty(insn, property, instructions, resultVar); CastInstruction castInsn = new CastInstruction(); castInsn.setReceiver(insn.getReceiver()); @@ -159,7 +159,7 @@ class ResourceProgramTransformer { private void getProperty(InvokeInstruction insn, String property, List instructions, Variable resultVar) { - Variable nameVar = program.createVariable(null); + Variable nameVar = program.createVariable(); StringConstantInstruction nameInsn = new StringConstantInstruction(); nameInsn.setConstant(property); nameInsn.setReceiver(nameVar); @@ -176,7 +176,7 @@ class ResourceProgramTransformer { private void getAndCastProperty(InvokeInstruction insn, String property, List instructions, Class primitive) { - Variable resultVar = program.createVariable(null); + Variable resultVar = program.createVariable(); getProperty(insn, property, instructions, resultVar); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); @@ -220,7 +220,7 @@ class ResourceProgramTransformer { } else if (type instanceof ValueType.Object) { switch (((ValueType.Object)type).getClassName()) { case "java.lang.String": { - Variable castVar = insn.getProgram().createVariable(null); + Variable castVar = insn.getProgram().createVariable(); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString", @@ -242,7 +242,7 @@ class ResourceProgramTransformer { private void setProperty(InvokeInstruction insn, String property, List instructions, Variable valueVar) { - Variable nameVar = program.createVariable(null); + Variable nameVar = program.createVariable(); StringConstantInstruction nameInsn = new StringConstantInstruction(); nameInsn.setConstant(property); nameInsn.setReceiver(nameVar); @@ -259,7 +259,7 @@ class ResourceProgramTransformer { private void castAndSetProperty(InvokeInstruction insn, String property, List instructions, Class primitive) { - Variable castVar = program.createVariable(null); + Variable castVar = program.createVariable(); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); String primitiveCapitalized = primitive.getName();