From 88dca1bd02f9121e89f572ad549480a4041a959e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 6 Mar 2019 16:51:01 +0300 Subject: [PATCH] Decrease memory consumption during compilation --- .../codegen/DefaultNamingStrategy.java | 66 ++++++-- core/src/main/java/org/teavm/cache/AstIO.java | 154 +++++++++++++----- .../cache/DiskCachedClassHolderSource.java | 5 +- .../org/teavm/cache/DiskMethodNodeCache.java | 4 +- .../org/teavm/cache/DiskProgramCache.java | 9 +- .../teavm/cache/InMemoryMethodNodeCache.java | 4 +- .../org/teavm/cache/InMemoryProgramCache.java | 4 +- .../main/java/org/teavm/cache/ProgramIO.java | 32 +++- .../java/org/teavm/cache/VarDataInput.java | 20 ++- .../java/org/teavm/cache/VarDataOutput.java | 14 +- .../information/DebugInformation.java | 4 + .../teavm/dependency/DependencyAnalyzer.java | 28 ++-- .../dependency/FastDependencyAnalyzer.java | 7 + .../org/teavm/dependency/FieldDependency.java | 4 +- .../teavm/dependency/MethodDependency.java | 4 +- .../org/teavm/model/MethodDescriptor.java | 45 +++-- .../java/org/teavm/model/MethodReference.java | 44 ++--- .../main/java/org/teavm/model/ValueType.java | 116 ++++++++----- .../java/org/teavm/cache/ProgramIOTest.java | 3 +- .../teavm/incremental/IncrementalTest.java | 6 +- .../java/org/teavm/tooling/TeaVMTool.java | 16 +- .../java/org/teavm/devserver/CodeServlet.java | 5 +- 22 files changed, 412 insertions(+), 182 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/codegen/DefaultNamingStrategy.java b/core/src/main/java/org/teavm/backend/javascript/codegen/DefaultNamingStrategy.java index a8d1dd225..e7ea7e108 100644 --- a/core/src/main/java/org/teavm/backend/javascript/codegen/DefaultNamingStrategy.java +++ b/core/src/main/java/org/teavm/backend/javascript/codegen/DefaultNamingStrategy.java @@ -17,13 +17,23 @@ package org.teavm.backend.javascript.codegen; import java.util.HashMap; import java.util.Map; -import org.teavm.model.*; +import org.teavm.model.AccessLevel; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.FieldReader; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReader; +import org.teavm.model.MethodReference; public class DefaultNamingStrategy implements NamingStrategy { + private static final byte NO_CLASSIFIER = 0; + private static final byte INIT_CLASSIFIER = 1; + private final AliasProvider aliasProvider; private final ClassReaderSource classSource; - private final Map aliases = new HashMap<>(); - private final Map privateAliases = new HashMap<>(); + private final Map aliases = new HashMap<>(); + private final Map privateAliases = new HashMap<>(); private final Map classAliases = new HashMap<>(); private final Map fieldAliases = new HashMap<>(); private final Map staticFieldAliases = new HashMap<>(); @@ -43,35 +53,33 @@ public class DefaultNamingStrategy implements NamingStrategy { @Override public String getNameFor(MethodDescriptor method) { - String key = method.toString(); - String alias = aliases.get(key); + String alias = aliases.get(method); if (alias == null) { alias = aliasProvider.getMethodAlias(method); - aliases.put(key, alias); + aliases.put(method, alias); } return alias; } @Override public ScopedName getFullNameFor(MethodReference method) { - return getFullNameFor(method, 'M'); + return getFullNameFor(method, NO_CLASSIFIER); } @Override public ScopedName getNameForInit(MethodReference method) { - return getFullNameFor(method, 'I'); + return getFullNameFor(method, INIT_CLASSIFIER); } - private ScopedName getFullNameFor(MethodReference method, char classifier) { + private ScopedName getFullNameFor(MethodReference method, byte classifier) { MethodReference originalMethod = method; method = getRealMethod(method); if (method == null) { method = originalMethod; } - MethodReference resolvedMethod = method; - return privateAliases.computeIfAbsent(classifier + method.toString(), - key -> aliasProvider.getStaticMethodAlias(resolvedMethod)); + return privateAliases.computeIfAbsent(new Key(classifier, method), + key -> aliasProvider.getStaticMethodAlias(key.data)); } @Override @@ -155,4 +163,38 @@ public class DefaultNamingStrategy implements NamingStrategy { } return fieldRef; } + + private final class Key { + final MethodReference data; + int hash; + final byte classifier; + + Key(byte classifier, MethodReference data) { + this.classifier = classifier; + this.data = data; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Key)) { + return false; + } + Key key = (Key) o; + return classifier == key.classifier && data.equals(key.data); + } + + @Override + public int hashCode() { + if (hash == 0) { + hash = (classifier * 31 + data.hashCode()) * 17; + if (hash == 0) { + hash++; + } + } + return hash; + } + } } diff --git a/core/src/main/java/org/teavm/cache/AstIO.java b/core/src/main/java/org/teavm/cache/AstIO.java index bd14165fe..036aa3a67 100644 --- a/core/src/main/java/org/teavm/cache/AstIO.java +++ b/core/src/main/java/org/teavm/cache/AstIO.java @@ -20,6 +20,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.teavm.ast.ArrayType; import org.teavm.ast.AssignmentStatement; @@ -82,16 +83,22 @@ public class AstIO { private static final UnaryOperation[] unaryOperations = UnaryOperation.values(); private final SymbolTable symbolTable; private final SymbolTable fileTable; + private final SymbolTable variableTable; private final Map statementMap = new HashMap<>(); private ReferenceCache referenceCache; + private TextLocation lastWrittenLocation; + private TextLocation lastReadLocation; - public AstIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable) { + public AstIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable, + SymbolTable variableTable) { this.referenceCache = referenceCache; this.symbolTable = symbolTable; this.fileTable = fileTable; + this.variableTable = variableTable; } public void write(VarDataOutput output, ControlFlowEntry[] cfg) throws IOException { + lastWrittenLocation = null; output.writeUnsigned(cfg.length); for (ControlFlowEntry entry : cfg) { writeLocation(output, entry.from); @@ -118,10 +125,11 @@ public class AstIO { private void write(VarDataOutput output, VariableNode variable) throws IOException { output.writeUnsigned(variable.getIndex()); output.writeUnsigned(variable.getType().ordinal()); - output.write(variable.getName()); + output.writeUnsigned(variable.getName() != null ? variableTable.lookup(variable.getName()) + 1 : 0); } public ControlFlowEntry[] readControlFlow(VarDataInput input) throws IOException { + lastReadLocation = null; int size = input.readUnsigned(); ControlFlowEntry[] result = new ControlFlowEntry[size]; for (int i = 0; i < size; ++i) { @@ -143,6 +151,7 @@ public class AstIO { for (int i = 0; i < varCount; ++i) { node.getVariables().add(readVariable(input)); } + lastReadLocation = null; node.setBody(readStatement(input)); return node; } @@ -151,7 +160,8 @@ public class AstIO { int index = input.readUnsigned(); VariableType type = VariableType.values()[input.readUnsigned()]; VariableNode variable = new VariableNode(index, type); - variable.setName(input.read()); + int nameIndex = input.readUnsigned(); + variable.setName(nameIndex != 0 ? variableTable.at(nameIndex - 1) : null); return variable; } @@ -162,10 +172,11 @@ public class AstIO { write(output, var); } try { - output.writeUnsigned(method.getBody().size()); - for (int i = 0; i < method.getBody().size(); ++i) { - method.getBody().get(i).getStatement().acceptVisitor(new NodeWriter(output)); - } + output.writeUnsigned(method.getBody().size()); + NodeWriter writer = new NodeWriter(output); + for (int i = 0; i < method.getBody().size(); ++i) { + method.getBody().get(i).getStatement().acceptVisitor(writer); + } } catch (IOExceptionWrapper e) { throw new IOException("Error writing method body", e.getCause()); } @@ -179,6 +190,7 @@ public class AstIO { node.getVariables().add(readVariable(input)); } int partCount = input.readUnsigned(); + lastReadLocation = null; for (int i = 0; i < partCount; ++i) { AsyncMethodPart part = new AsyncMethodPart(); part.setStatement(readStatement(input)); @@ -200,14 +212,21 @@ public class AstIO { private void writeLocation(VarDataOutput output, TextLocation location) throws IOException { if (location == null || location.getFileName() == null) { output.writeUnsigned(0); + lastWrittenLocation = null; + } else if (lastWrittenLocation != null && lastWrittenLocation.getFileName().equals(location.getFileName())) { + output.writeUnsigned(1); + output.writeSigned(location.getLine() - lastWrittenLocation.getLine()); + lastWrittenLocation = location; } else { - output.writeUnsigned(fileTable.lookup(location.getFileName()) + 1); + output.writeUnsigned(fileTable.lookup(location.getFileName()) + 2); output.writeUnsigned(location.getLine()); + lastWrittenLocation = location; } } private class NodeWriter implements ExprVisitor, StatementVisitor { private final VarDataOutput output; + private TextLocation lastLocation; NodeWriter(VarDataOutput output) { super(); @@ -220,7 +239,22 @@ public class AstIO { } private void writeLocation(TextLocation location) throws IOException { - AstIO.this.writeLocation(output, location); + if (Objects.equals(location, lastLocation)) { + return; + } + if (location == null || location.getFileName() == null) { + output.writeUnsigned(127); + lastLocation = null; + } else if (lastLocation != null && lastLocation.getFileName().equals(location.getFileName())) { + output.writeUnsigned(126); + output.writeSigned(location.getLine() - lastLocation.getLine()); + lastLocation = location; + } else { + output.writeUnsigned(125); + output.writeUnsigned(fileTable.lookup(location.getFileName())); + output.writeUnsigned(location.getLine()); + lastLocation = location; + } } private void writeSequence(List sequence) throws IOException { @@ -233,8 +267,8 @@ public class AstIO { @Override public void visit(AssignmentStatement statement) { try { - output.writeUnsigned(statement.getLeftValue() != null ? 0 : 1); writeLocation(statement.getLocation()); + output.writeUnsigned(statement.getLeftValue() != null ? 0 : 1); if (statement.getLeftValue() != null) { writeExpr(statement.getLeftValue()); } @@ -316,8 +350,8 @@ public class AstIO { @Override public void visit(BreakStatement statement) { try { - output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9); writeLocation(statement.getLocation()); + output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9); if (statement.getTarget() != null && statement.getTarget().getId() != null) { output.write(statement.getTarget().getId()); } @@ -329,8 +363,8 @@ public class AstIO { @Override public void visit(ContinueStatement statement) { try { - output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11); writeLocation(statement.getLocation()); + output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11); if (statement.getTarget() != null && statement.getTarget().getId() != null) { output.write(statement.getTarget().getId()); } @@ -342,8 +376,8 @@ public class AstIO { @Override public void visit(ReturnStatement statement) { try { - output.writeUnsigned(statement.getResult() != null ? 12 : 13); writeLocation(statement.getLocation()); + output.writeUnsigned(statement.getResult() != null ? 12 : 13); if (statement.getResult() != null) { writeExpr(statement.getResult()); } @@ -355,8 +389,8 @@ public class AstIO { @Override public void visit(ThrowStatement statement) { try { - output.writeUnsigned(14); writeLocation(statement.getLocation()); + output.writeUnsigned(14); writeExpr(statement.getException()); } catch (IOException e) { throw new IOExceptionWrapper(e); @@ -366,8 +400,8 @@ public class AstIO { @Override public void visit(InitClassStatement statement) { try { - output.writeUnsigned(15); writeLocation(statement.getLocation()); + output.writeUnsigned(15); output.writeUnsigned(symbolTable.lookup(statement.getClassName())); } catch (IOException e) { throw new IOExceptionWrapper(e); @@ -402,8 +436,8 @@ public class AstIO { @Override public void visit(MonitorEnterStatement statement) { try { - output.writeUnsigned(18); writeLocation(statement.getLocation()); + output.writeUnsigned(18); writeExpr(statement.getObjectRef()); } catch (IOException e) { throw new IOExceptionWrapper(e); @@ -413,8 +447,8 @@ public class AstIO { @Override public void visit(MonitorExitStatement statement) { try { - output.writeUnsigned(19); writeLocation(statement.getLocation()); + output.writeUnsigned(19); writeExpr(statement.getObjectRef()); } catch (IOException e) { throw new IOExceptionWrapper(e); @@ -636,18 +670,41 @@ public class AstIO { private TextLocation readLocation(VarDataInput input) throws IOException { int fileIndex = input.readUnsigned(); if (fileIndex == 0) { - return null; + lastReadLocation = null; + } else if (fileIndex == 1) { + lastReadLocation = new TextLocation(lastReadLocation.getFileName(), + lastReadLocation.getLine() + input.readSigned()); } else { - return new TextLocation(fileTable.at(fileIndex - 1), input.readUnsigned()); + lastReadLocation = new TextLocation(fileTable.at(fileIndex - 2), input.readUnsigned()); + return lastReadLocation; } + return lastReadLocation; + } + + private int readNodeLocation(int type, VarDataInput input) throws IOException { + switch (type) { + case 127: + lastReadLocation = null; + break; + case 126: + lastReadLocation = new TextLocation(lastReadLocation.getFileName(), + lastReadLocation.getLine() + input.readSigned()); + break; + case 125: + lastReadLocation = new TextLocation(fileTable.at(input.readUnsigned()), input.readUnsigned()); + break; + default: + return type; + } + return input.readUnsigned(); } private Statement readStatement(VarDataInput input) throws IOException { - int type = input.readUnsigned(); + int type = readNodeLocation(input.readUnsigned(), input); switch (type) { case 0: { AssignmentStatement stmt = new AssignmentStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setLeftValue(readExpr(input)); stmt.setRightValue(readExpr(input)); stmt.setAsync(input.readUnsigned() != 0); @@ -655,7 +712,7 @@ public class AstIO { } case 1: { AssignmentStatement stmt = new AssignmentStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setRightValue(readExpr(input)); stmt.setAsync(input.readUnsigned() != 0); return stmt; @@ -721,46 +778,46 @@ public class AstIO { } case 8: { BreakStatement stmt = new BreakStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setTarget(statementMap.get(input.read())); return stmt; } case 9: { BreakStatement stmt = new BreakStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); return stmt; } case 10: { ContinueStatement stmt = new ContinueStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setTarget(statementMap.get(input.read())); return stmt; } case 11: { ContinueStatement stmt = new ContinueStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); return stmt; } case 12: { ReturnStatement stmt = new ReturnStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setResult(readExpr(input)); return stmt; } case 13: { ReturnStatement stmt = new ReturnStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); return stmt; } case 14: { ThrowStatement stmt = new ThrowStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setException(readExpr(input)); return stmt; } case 15: { InitClassStatement stmt = new InitClassStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setClassName(symbolTable.at(input.readUnsigned())); return stmt; } @@ -785,13 +842,13 @@ public class AstIO { } case 18: { MonitorEnterStatement stmt = new MonitorEnterStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setObjectRef(readExpr(input)); return stmt; } case 19: { MonitorExitStatement stmt = new MonitorExitStatement(); - stmt.setLocation(readLocation(input)); + stmt.setLocation(lastReadLocation); stmt.setObjectRef(readExpr(input)); return stmt; } @@ -808,17 +865,11 @@ public class AstIO { } private Expr readExpr(VarDataInput input) throws IOException { - TextLocation location = readLocation(input); - Expr expr = readExprWithoutLocation(input); - expr.setLocation(location); - return expr; - } - - private Expr readExprWithoutLocation(VarDataInput input) throws IOException { - int type = input.readUnsigned(); + int type = readNodeLocation(input.readUnsigned(), input); switch (type) { case 0: { BinaryExpr expr = new BinaryExpr(); + expr.setLocation(lastReadLocation); expr.setOperation(binaryOperations[input.readUnsigned()]); int valueType = input.readUnsigned(); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null); @@ -828,6 +879,7 @@ public class AstIO { } case 1: { UnaryExpr expr = new UnaryExpr(); + expr.setLocation(lastReadLocation); expr.setOperation(unaryOperations[input.readUnsigned()]); int valueType = input.readUnsigned(); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null); @@ -836,16 +888,20 @@ public class AstIO { } case 2: { ConditionalExpr expr = new ConditionalExpr(); + expr.setLocation(lastReadLocation); expr.setCondition(readExpr(input)); expr.setConsequent(readExpr(input)); expr.setAlternative(readExpr(input)); return expr; } case 3: { - return new ConstantExpr(); + ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); + return expr; } case 4: { ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); expr.setValue(input.readSigned()); return expr; } @@ -856,31 +912,37 @@ public class AstIO { } case 6: { ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); expr.setValue(input.readFloat()); return expr; } case 7: { ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); expr.setValue(input.readDouble()); return expr; } case 8: { ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); expr.setValue(input.read()); return expr; } case 9: { ConstantExpr expr = new ConstantExpr(); + expr.setLocation(lastReadLocation); expr.setValue(ValueType.parse(symbolTable.at(input.readUnsigned()))); return expr; } case 10: { VariableExpr expr = new VariableExpr(); + expr.setLocation(lastReadLocation); expr.setIndex(input.readUnsigned()); return expr; } case 11: { SubscriptExpr expr = new SubscriptExpr(); + expr.setLocation(lastReadLocation); expr.setArray(readExpr(input)); expr.setIndex(readExpr(input)); expr.setType(ArrayType.values()[input.readUnsigned()]); @@ -888,6 +950,7 @@ public class AstIO { } case 12: { UnwrapArrayExpr expr = new UnwrapArrayExpr(ArrayType.values()[input.readUnsigned()]); + expr.setLocation(lastReadLocation); expr.setArray(readExpr(input)); return expr; } @@ -901,6 +964,7 @@ public class AstIO { return parseInvocationExpr(InvocationType.DYNAMIC, input); case 17: { QualificationExpr expr = new QualificationExpr(); + expr.setLocation(lastReadLocation); String className = symbolTable.at(input.readUnsigned()); String fieldName = symbolTable.at(input.readUnsigned()); expr.setField(new FieldReference(className, fieldName)); @@ -908,6 +972,7 @@ public class AstIO { } case 18: { QualificationExpr expr = new QualificationExpr(); + expr.setLocation(lastReadLocation); expr.setQualified(readExpr(input)); String className = symbolTable.at(input.readUnsigned()); String fieldName = symbolTable.at(input.readUnsigned()); @@ -916,17 +981,20 @@ public class AstIO { } case 19: { NewExpr expr = new NewExpr(); + expr.setLocation(lastReadLocation); expr.setConstructedClass(symbolTable.at(input.readUnsigned())); return expr; } case 20: { NewArrayExpr expr = new NewArrayExpr(); + expr.setLocation(lastReadLocation); expr.setLength(readExpr(input)); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned()))); return expr; } case 21: { NewMultiArrayExpr expr = new NewMultiArrayExpr(); + expr.setLocation(lastReadLocation); int dimensionCount = input.readUnsigned(); for (int i = 0; i < dimensionCount; ++i) { expr.getDimensions().add(readExpr(input)); @@ -936,18 +1004,21 @@ public class AstIO { } case 22: { InstanceOfExpr expr = new InstanceOfExpr(); + expr.setLocation(lastReadLocation); expr.setExpr(readExpr(input)); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned()))); return expr; } case 23: { CastExpr expr = new CastExpr(); + expr.setLocation(lastReadLocation); expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setValue(readExpr(input)); return expr; } case 24: { PrimitiveCastExpr expr = new PrimitiveCastExpr(); + expr.setLocation(lastReadLocation); expr.setSource(OperationType.values()[input.readUnsigned()]); expr.setTarget(OperationType.values()[input.readUnsigned()]); expr.setValue(readExpr(input)); @@ -960,6 +1031,7 @@ public class AstIO { private InvocationExpr parseInvocationExpr(InvocationType invocationType, VarDataInput input) throws IOException { InvocationExpr expr = new InvocationExpr(); + expr.setLocation(lastReadLocation); expr.setType(invocationType); String className = symbolTable.at(input.readUnsigned()); String signature = symbolTable.at(input.readUnsigned()); diff --git a/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java b/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java index dd268fafd..ce9a6d303 100644 --- a/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java +++ b/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java @@ -64,12 +64,13 @@ public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStat private ProgramIO programIO; public DiskCachedClassHolderSource(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, - SymbolTable fileTable, ClassHolderSource innerSource, ClassDateProvider classDateProvider) { + SymbolTable fileTable, SymbolTable variableTable, ClassHolderSource innerSource, + ClassDateProvider classDateProvider) { this.directory = directory; this.symbolTable = symbolTable; this.innerSource = innerSource; this.classDateProvider = classDateProvider; - programIO = new ProgramIO(referenceCache, symbolTable, fileTable); + programIO = new ProgramIO(referenceCache, symbolTable, fileTable, variableTable); } @Override diff --git a/core/src/main/java/org/teavm/cache/DiskMethodNodeCache.java b/core/src/main/java/org/teavm/cache/DiskMethodNodeCache.java index 56af8c319..726d4fd85 100644 --- a/core/src/main/java/org/teavm/cache/DiskMethodNodeCache.java +++ b/core/src/main/java/org/teavm/cache/DiskMethodNodeCache.java @@ -42,9 +42,9 @@ public class DiskMethodNodeCache implements MethodNodeCache { private final Set newAsyncMethods = new HashSet<>(); public DiskMethodNodeCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, - SymbolTable fileTable) { + SymbolTable fileTable, SymbolTable variableTable) { this.directory = directory; - astIO = new AstIO(referenceCache, symbolTable, fileTable); + astIO = new AstIO(referenceCache, symbolTable, fileTable, variableTable); } @Override diff --git a/core/src/main/java/org/teavm/cache/DiskProgramCache.java b/core/src/main/java/org/teavm/cache/DiskProgramCache.java index 6123b3af7..0a7e572ad 100644 --- a/core/src/main/java/org/teavm/cache/DiskProgramCache.java +++ b/core/src/main/java/org/teavm/cache/DiskProgramCache.java @@ -27,13 +27,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Supplier; -import org.teavm.model.ClassReaderSource; import org.teavm.model.MethodReference; import org.teavm.model.Program; import org.teavm.model.ProgramCache; @@ -46,9 +44,9 @@ public class DiskProgramCache implements ProgramCache { private Set newMethods = new HashSet<>(); public DiskProgramCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, - SymbolTable fileTable) { + SymbolTable fileTable, SymbolTable variableTable) { this.directory = directory; - programIO = new ProgramIO(referenceCache, symbolTable, fileTable); + programIO = new ProgramIO(referenceCache, symbolTable, fileTable, variableTable); } @Override @@ -90,8 +88,7 @@ public class DiskProgramCache implements ProgramCache { newMethods.add(method); } - public void flush(ClassReaderSource classSource) throws IOException { - Date currentTime = new Date(); + public void flush() throws IOException { for (MethodReference method : newMethods) { Item item = cache.get(method); File file = getMethodFile(method); diff --git a/core/src/main/java/org/teavm/cache/InMemoryMethodNodeCache.java b/core/src/main/java/org/teavm/cache/InMemoryMethodNodeCache.java index 55983acd3..ca8d25702 100644 --- a/core/src/main/java/org/teavm/cache/InMemoryMethodNodeCache.java +++ b/core/src/main/java/org/teavm/cache/InMemoryMethodNodeCache.java @@ -36,8 +36,8 @@ public class InMemoryMethodNodeCache implements MethodNodeCache { private AstIO io; public InMemoryMethodNodeCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable, - InMemorySymbolTable fileSymbolTable) { - io = new AstIO(referenceCache, symbolTable, fileSymbolTable); + InMemorySymbolTable fileSymbolTable, InMemorySymbolTable variableSymbolTable) { + io = new AstIO(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable); } @Override diff --git a/core/src/main/java/org/teavm/cache/InMemoryProgramCache.java b/core/src/main/java/org/teavm/cache/InMemoryProgramCache.java index 9107327ee..d90e08473 100644 --- a/core/src/main/java/org/teavm/cache/InMemoryProgramCache.java +++ b/core/src/main/java/org/teavm/cache/InMemoryProgramCache.java @@ -33,8 +33,8 @@ public class InMemoryProgramCache implements ProgramCache { private ProgramIO io; public InMemoryProgramCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable, - InMemorySymbolTable fileSymbolTable) { - io = new ProgramIO(referenceCache, symbolTable, fileSymbolTable); + InMemorySymbolTable fileSymbolTable, InMemorySymbolTable variableSymbolTable) { + io = new ProgramIO(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable); } @Override diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index f656c129e..ce062286c 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -85,6 +85,7 @@ import org.teavm.model.instructions.UnwrapArrayInstruction; public class ProgramIO { private SymbolTable symbolTable; private SymbolTable fileTable; + private SymbolTable variableTable; private ReferenceCache referenceCache; private static BinaryOperation[] binaryOperations = BinaryOperation.values(); private static NumericOperandType[] numericOperandTypes = NumericOperandType.values(); @@ -94,10 +95,12 @@ public class ProgramIO { private static BinaryBranchingCondition[] binaryBranchingConditions = BinaryBranchingCondition.values(); private static ArrayElementType[] arrayElementTypes = ArrayElementType.values(); - public ProgramIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable) { + public ProgramIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable, + SymbolTable variableTable) { this.referenceCache = referenceCache; this.symbolTable = symbolTable; this.fileTable = fileTable; + this.variableTable = variableTable; } public void write(Program program, OutputStream output) throws IOException { @@ -107,7 +110,7 @@ public class ProgramIO { for (int i = 0; i < program.variableCount(); ++i) { Variable var = program.variableAt(i); data.writeUnsigned(var.getRegister()); - data.write(var.getDebugName()); + data.writeUnsigned(var.getDebugName() != null ? variableTable.lookup(var.getDebugName()) + 1 : 0); } for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock basicBlock = program.basicBlockAt(i); @@ -133,13 +136,20 @@ public class ProgramIO { for (Instruction insn : basicBlock) { try { if (!Objects.equals(location, insn.getLocation())) { - location = insn.getLocation(); - if (location == null || location.getFileName() == null || location.getLine() < 0) { + TextLocation newLocation = insn.getLocation(); + if (newLocation == null || newLocation.getFileName() == null || newLocation.getLine() < 0) { data.writeUnsigned(1); + location = null; } else { - data.writeUnsigned(2); - data.writeUnsigned(fileTable.lookup(location.getFileName())); - data.writeUnsigned(location.getLine()); + if (location != null && location.getFileName().equals(newLocation.getFileName())) { + data.writeUnsigned(127); + data.writeSigned(newLocation.getLine() - location.getLine()); + } else { + data.writeUnsigned(2); + data.writeUnsigned(fileTable.lookup(newLocation.getFileName())); + data.writeUnsigned(newLocation.getLine()); + } + location = newLocation; } } insn.acceptVisitor(insnWriter); @@ -159,7 +169,8 @@ public class ProgramIO { for (int i = 0; i < varCount; ++i) { Variable var = program.createVariable(); var.setRegister(data.readUnsigned()); - var.setDebugName(referenceCache.getCached(data.read())); + int nameIndex = data.readUnsigned(); + var.setDebugName(nameIndex != 0 ? referenceCache.getCached(variableTable.at(nameIndex - 1)) : null); } for (int i = 0; i < basicBlockCount; ++i) { program.createBasicBlock(); @@ -212,6 +223,11 @@ public class ProgramIO { location = new TextLocation(file, line); break; } + case 127: { + int line = location.getLine() + data.readSigned(); + location = new TextLocation(location.getFileName(), line); + break; + } default: { Instruction insn = readInstruction(insnType, program, data); insn.setLocation(location); diff --git a/core/src/main/java/org/teavm/cache/VarDataInput.java b/core/src/main/java/org/teavm/cache/VarDataInput.java index beb73d771..0cd611066 100644 --- a/core/src/main/java/org/teavm/cache/VarDataInput.java +++ b/core/src/main/java/org/teavm/cache/VarDataInput.java @@ -69,7 +69,15 @@ public class VarDataInput { } public float readFloat() throws IOException { - int exponent = readSigned() + 127; + int exponent = readUnsigned(); + if (exponent == 0) { + return 0; + } + + exponent--; + exponent = (exponent & 1) == 0 ? exponent >>> 1 : -(exponent >>> 1); + exponent += 127; + int mantissa = Integer.reverse(readUnsigned()) >>> 8; boolean sign = (mantissa & (1 << 23)) != 0; @@ -83,7 +91,15 @@ public class VarDataInput { } public double readDouble() throws IOException { - int exponent = readSigned() + 1023; + int exponent = readUnsigned(); + if (exponent == 0) { + return 0; + } + + exponent--; + exponent = (exponent & 1) == 0 ? exponent >>> 1 : -(exponent >>> 1); + exponent += 1023; + long mantissa = Long.reverse(readUnsignedLong()) >>> 11; boolean sign = (mantissa & (1L << 52)) != 0; diff --git a/core/src/main/java/org/teavm/cache/VarDataOutput.java b/core/src/main/java/org/teavm/cache/VarDataOutput.java index 9a7bd571a..e64405457 100644 --- a/core/src/main/java/org/teavm/cache/VarDataOutput.java +++ b/core/src/main/java/org/teavm/cache/VarDataOutput.java @@ -53,6 +53,10 @@ public class VarDataOutput implements Closeable { } public void writeFloat(float value) throws IOException { + if (value == 0) { + writeUnsigned(0); + return; + } int bits = Float.floatToRawIntBits(value); boolean sign = (bits & (1 << 31)) != 0; int exponent = (bits >> 23) & ((1 << 8) - 1); @@ -60,11 +64,16 @@ public class VarDataOutput implements Closeable { if (sign) { mantissa |= 1 << 23; } - writeSigned(exponent - 127); + exponent -= 127; + writeUnsigned(1 + (exponent > 0 ? exponent << 1 : 1 | (-exponent << 1))); writeUnsigned(Integer.reverse(mantissa << 8)); } public void writeDouble(double value) throws IOException { + if (value == 0) { + writeUnsigned(0); + return; + } long bits = Double.doubleToRawLongBits(value); boolean sign = (bits & (1L << 63)) != 0; int exponent = (int) (bits >> 52) & ((1 << 11) - 1); @@ -72,7 +81,8 @@ public class VarDataOutput implements Closeable { if (sign) { mantissa |= 1L << 52; } - writeSigned(exponent - 1023); + exponent -= 1023; + writeUnsigned(1 + (exponent > 0 ? exponent << 1 : 1 | (-exponent << 1))); writeUnsigned(Long.reverse(mantissa << 11)); } diff --git a/core/src/main/java/org/teavm/debugging/information/DebugInformation.java b/core/src/main/java/org/teavm/debugging/information/DebugInformation.java index 557dbb7ca..6e6592169 100644 --- a/core/src/main/java/org/teavm/debugging/information/DebugInformation.java +++ b/core/src/main/java/org/teavm/debugging/information/DebugInformation.java @@ -53,6 +53,10 @@ public class DebugInformation { MethodTree methodTree; ReferenceCache referenceCache; + public DebugInformation() { + this(new ReferenceCache()); + } + public DebugInformation(ReferenceCache referenceCache) { this.referenceCache = referenceCache; } diff --git a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java index 64e3d601f..dfa133ed8 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java +++ b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java @@ -26,7 +26,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Deque; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -37,7 +36,6 @@ import org.objectweb.asm.tree.ClassNode; import org.teavm.cache.IncrementalDependencyProvider; import org.teavm.cache.IncrementalDependencyRegistration; import org.teavm.callgraph.CallGraph; -import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.DefaultCallGraph; import org.teavm.common.CachedMapper; import org.teavm.common.Mapper; @@ -429,8 +427,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo { private ClassDependency createClassDependency(String className) { ClassReader cls = classSource.get(className); - ClassDependency dependency = new ClassDependency(this, className, cls); - return dependency; + return new ClassDependency(this, className, cls); } public MethodDependency linkMethod(String className, MethodDescriptor descriptor) { @@ -527,8 +524,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo { return classCache.getCachedPreimages(); } - private Set fieldsAddedByRoot = new HashSet<>(); - public FieldDependency linkField(FieldReference fieldRef) { FieldDependency dep = fieldCache.map(fieldRef); if (!dep.activated) { @@ -746,9 +741,25 @@ public abstract class DependencyAnalyzer implements DependencyInfo { } } + for (Map map : methodCache.values()) { + for (MethodDependency methodDependency : map.values()) { + methodDependency.locationListeners = null; + methodDependency.locations = null; + } + } + + for (FieldReference fieldRef : fieldCache.getCachedPreimages()) { + FieldDependency field = fieldCache.getKnown(fieldRef); + if (field != null) { + field.locationListeners = null; + field.locations = null; + } + } + allNodes.clear(); classSource.cleanup(); agent.cleanup(); + listeners.clear(); } public void cleanupTypes() { @@ -857,10 +868,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo { return; } - CallGraphNode caller = callGraph.getNode(methodDep.getReference()); - ProgramEmitter pe = ProgramEmitter.create(program, classHierarchy); - boolean hasIndy = false; BasicBlockSplitter splitter = new BasicBlockSplitter(program); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); @@ -885,7 +893,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo { continue; } - hasIndy = true; BasicBlock splitBlock = splitter.split(block, insn); pe.enter(block); @@ -910,7 +917,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo { pe.addInstruction(assign); } pe.jump(splitBlock); - block = splitBlock; } } splitter.fixProgram(); diff --git a/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java b/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java index a914bb1a9..cadd1c614 100644 --- a/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java +++ b/core/src/main/java/org/teavm/dependency/FastDependencyAnalyzer.java @@ -189,4 +189,11 @@ public class FastDependencyAnalyzer extends DependencyAnalyzer { boolean domainOptimizationEnabled() { return false; } + + @Override + public void cleanup() { + virtualCallConsumers.clear(); + subtypeNodes.clear(); + super.cleanup(); + } } diff --git a/core/src/main/java/org/teavm/dependency/FieldDependency.java b/core/src/main/java/org/teavm/dependency/FieldDependency.java index 253a31415..5df70a43a 100644 --- a/core/src/main/java/org/teavm/dependency/FieldDependency.java +++ b/core/src/main/java/org/teavm/dependency/FieldDependency.java @@ -28,8 +28,8 @@ public class FieldDependency implements FieldDependencyInfo { DependencyNode value; private FieldReader field; private FieldReference reference; - private List locationListeners; - private Set locations; + List locationListeners; + Set locations; boolean activated; FieldDependency(DependencyNode value, FieldReader field, FieldReference reference) { diff --git a/core/src/main/java/org/teavm/dependency/MethodDependency.java b/core/src/main/java/org/teavm/dependency/MethodDependency.java index b68523316..db0a60806 100644 --- a/core/src/main/java/org/teavm/dependency/MethodDependency.java +++ b/core/src/main/java/org/teavm/dependency/MethodDependency.java @@ -38,8 +38,8 @@ public class MethodDependency implements MethodDependencyInfo { boolean external; DependencyPlugin dependencyPlugin; boolean dependencyPluginAttached; - private List locationListeners; - private Set locations; + List locationListeners; + Set locations; boolean activated; MethodDependency(DependencyAnalyzer dependencyAnalyzer, DependencyNode[] variableNodes, int parameterCount, diff --git a/core/src/main/java/org/teavm/model/MethodDescriptor.java b/core/src/main/java/org/teavm/model/MethodDescriptor.java index 6fdbf3ee7..35d0ae460 100644 --- a/core/src/main/java/org/teavm/model/MethodDescriptor.java +++ b/core/src/main/java/org/teavm/model/MethodDescriptor.java @@ -20,7 +20,7 @@ import java.util.Arrays; public class MethodDescriptor { private String name; private ValueType[] signature; - private volatile String reprCache; + private int hash; public MethodDescriptor(String name, ValueType... signature) { if (signature.length < 1) { @@ -70,10 +70,7 @@ public class MethodDescriptor { @Override public String toString() { - if (reprCache == null) { - reprCache = name + signatureToString(); - } - return reprCache; + return name + signatureToString(); } public String signatureToString() { @@ -140,17 +137,43 @@ public class MethodDescriptor { @Override public int hashCode() { - return toString().hashCode(); + if (hash == 0) { + hash = name.hashCode(); + for (ValueType param : signature) { + hash = 31 * hash + param.hashCode(); + } + if (hash == 0) { + hash++; + } + } + + return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; - } - if (!(obj instanceof MethodDescriptor)) { - return false; - } - return toString().equals(obj.toString()); + } + if (!(obj instanceof MethodDescriptor)) { + return false; + } + MethodDescriptor that = (MethodDescriptor) obj; + + if (signature.length != that.signature.length) { + return false; + } + + if (!name.equals(that.name)) { + return false; + } + + for (int i = 0; i < signature.length; ++i) { + if (!signature[i].equals(that.signature[i])) { + return false; + } + } + + return true; } } diff --git a/core/src/main/java/org/teavm/model/MethodReference.java b/core/src/main/java/org/teavm/model/MethodReference.java index 4d4dd13c5..6f0ed370c 100644 --- a/core/src/main/java/org/teavm/model/MethodReference.java +++ b/core/src/main/java/org/teavm/model/MethodReference.java @@ -35,16 +35,12 @@ import java.util.stream.Stream; */ public class MethodReference implements Serializable { private String className; - private String name; - private ValueType[] signature; private transient MethodDescriptor descriptor; - private transient String reprCache; + private int hash; public MethodReference(String className, MethodDescriptor descriptor) { this.className = className; this.descriptor = descriptor; - this.name = descriptor.getName(); - this.signature = descriptor.getSignature(); } /** @@ -64,9 +60,7 @@ public class MethodReference implements Serializable { * a type of a returning value, and all the remaining elements are types of arguments. */ public MethodReference(String className, String name, ValueType... signature) { - this.className = className; - this.name = name; - this.signature = Arrays.copyOf(signature, signature.length); + this(className, new MethodDescriptor(name, signature)); } public MethodReference(Class cls, String name, Class... signature) { @@ -86,42 +80,42 @@ public class MethodReference implements Serializable { } public MethodDescriptor getDescriptor() { - if (descriptor == null) { - descriptor = new MethodDescriptor(name, signature); - } return descriptor; } public int parameterCount() { - return signature.length - 1; + return descriptor.parameterCount(); } public ValueType parameterType(int index) { - if (index >= signature.length + 1) { - throw new IndexOutOfBoundsException("Index " + index + " is greater than size " + (signature.length - 1)); - } - return signature[index]; + return descriptor.parameterType(index); } public ValueType[] getParameterTypes() { - return Arrays.copyOf(signature, signature.length - 1); + return descriptor.getParameterTypes(); } public ValueType[] getSignature() { - return Arrays.copyOf(signature, signature.length); + return descriptor.getSignature(); } public ValueType getReturnType() { - return signature[signature.length - 1]; + return descriptor.getResultType(); } public String getName() { - return name; + return descriptor.getName(); } @Override public int hashCode() { - return toString().hashCode(); + if (hash == 0) { + hash = (className.hashCode() * 31 + descriptor.hashCode()) * 17; + if (hash == 0) { + hash++; + } + } + return hash; } @Override @@ -132,17 +126,15 @@ public class MethodReference implements Serializable { if (!(obj instanceof MethodReference)) { return false; } + MethodReference other = (MethodReference) obj; - return toString().equals(other.toString()); + return className.equals(other.className) && descriptor.equals(other.descriptor); } @Override @JsonValue public String toString() { - if (reprCache == null) { - reprCache = className + "." + getDescriptor().toString(); - } - return reprCache; + return className + "." + getDescriptor().toString(); } @JsonCreator diff --git a/core/src/main/java/org/teavm/model/ValueType.java b/core/src/main/java/org/teavm/model/ValueType.java index d554f643d..767b24372 100644 --- a/core/src/main/java/org/teavm/model/ValueType.java +++ b/core/src/main/java/org/teavm/model/ValueType.java @@ -20,7 +20,6 @@ import java.util.*; import java.util.stream.Collectors; public abstract class ValueType implements Serializable { - volatile String reprCache; private static final Map, ValueType> primitiveMap = new HashMap<>(); private ValueType() { @@ -28,6 +27,7 @@ public abstract class ValueType implements Serializable { public static class Object extends ValueType { private String className; + private int hash; public Object(String className) { this.className = className; @@ -39,23 +39,45 @@ public abstract class ValueType implements Serializable { @Override public String toString() { - if (reprCache == null) { - reprCache = "L" + className.replace('.', '/') + ";"; - } - return reprCache; + return "L" + className.replace('.', '/') + ";"; } @Override public boolean isObject(String className) { return this.className.equals(className); } + + @Override + public boolean equals(java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Object)) { + return false; + } + Object that = (Object) obj; + return that.className.equals(className); + } + + @Override + public int hashCode() { + if (hash == 0) { + hash = 85396296 ^ (className.hashCode() * 167); + if (hash == 0) { + ++hash; + } + } + return hash; + } } public static class Primitive extends ValueType { private PrimitiveType kind; + private int hash; - Primitive(PrimitiveType kind) { + private Primitive(PrimitiveType kind) { this.kind = kind; + hash = 17988782 ^ (kind.ordinal() * 31); } public PrimitiveType getKind() { @@ -64,13 +86,6 @@ public abstract class ValueType implements Serializable { @Override public String toString() { - if (reprCache == null) { - reprCache = createString(); - } - return reprCache; - } - - private String createString() { switch (kind) { case BOOLEAN: return "Z"; @@ -97,10 +112,21 @@ public abstract class ValueType implements Serializable { public boolean isObject(String cls) { return false; } + + @Override + public boolean equals(java.lang.Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return hash; + } } public static class Array extends ValueType { private ValueType itemType; + private int hash; public Array(ValueType itemType) { this.itemType = itemType; @@ -112,19 +138,43 @@ public abstract class ValueType implements Serializable { @Override public String toString() { - if (reprCache == null) { - reprCache = "[" + itemType.toString(); - } - return reprCache; + return "[" + itemType; } @Override public boolean isObject(String cls) { return false; } + + @Override + public boolean equals(java.lang.Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Array)) { + return false; + } + + Array that = (Array) obj; + return itemType.equals(that.itemType); + } + + @Override + public int hashCode() { + if (hash == 0) { + hash = 27039876 ^ (itemType.hashCode() * 193); + if (hash == 0) { + ++hash; + } + } + return hash; + } } public static class Void extends ValueType { + private Void() { + } + @Override public String toString() { return "V"; @@ -134,12 +184,15 @@ public abstract class ValueType implements Serializable { public boolean isObject(String cls) { return false; } - } - public static class Null extends ValueType { @Override - public boolean isObject(String cls) { - return false; + public boolean equals(java.lang.Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return 53604390; } } @@ -161,9 +214,6 @@ public abstract class ValueType implements Serializable { public static final Primitive CHARACTER = new Primitive(PrimitiveType.CHARACTER); - public static final Null NULL = new Null(); - - static { primitiveMap.put(boolean.class, BOOLEAN); primitiveMap.put(char.class, CHARACTER); @@ -227,7 +277,7 @@ public abstract class ValueType implements Serializable { types.add(type); index = nextIndex; } - return types.toArray(new ValueType[types.size()]); + return types.toArray(new ValueType[0]); } private static int cut(String text, int index) { @@ -344,20 +394,4 @@ public abstract class ValueType implements Serializable { return ValueType.object(cls.getName()); } } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - @Override - public boolean equals(java.lang.Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof ValueType)) { - return false; - } - return toString().equals(obj.toString()); - } } diff --git a/core/src/test/java/org/teavm/cache/ProgramIOTest.java b/core/src/test/java/org/teavm/cache/ProgramIOTest.java index a0efe92bf..985810ff8 100644 --- a/core/src/test/java/org/teavm/cache/ProgramIOTest.java +++ b/core/src/test/java/org/teavm/cache/ProgramIOTest.java @@ -158,7 +158,8 @@ public class ProgramIOTest { private Program inputOutput(Program program) { InMemorySymbolTable symbolTable = new InMemorySymbolTable(); InMemorySymbolTable fileTable = new InMemorySymbolTable(); - ProgramIO programIO = new ProgramIO(new ReferenceCache(), symbolTable, fileTable); + InMemorySymbolTable variableTable = new InMemorySymbolTable(); + ProgramIO programIO = new ProgramIO(new ReferenceCache(), symbolTable, fileTable, variableTable); try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { programIO.write(program, output); try (ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray())) { diff --git a/tests/src/test/java/org/teavm/incremental/IncrementalTest.java b/tests/src/test/java/org/teavm/incremental/IncrementalTest.java index 782b5cba0..5704a0d4b 100644 --- a/tests/src/test/java/org/teavm/incremental/IncrementalTest.java +++ b/tests/src/test/java/org/teavm/incremental/IncrementalTest.java @@ -239,7 +239,8 @@ public class IncrementalTest { boolean capturing; CapturingMethodNodeCache() { - super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable()); + super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable(), + new InMemorySymbolTable()); } @Override @@ -264,7 +265,8 @@ public class IncrementalTest { boolean capturing; CapturingProgramCache() { - super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable()); + super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable(), + new InMemorySymbolTable()); } @Override diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index aa4b10143..c809fff65 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -88,6 +88,7 @@ public class TeaVMTool { private DiskMethodNodeCache astCache; private FileSymbolTable symbolTable; private FileSymbolTable fileTable; + private FileSymbolTable variableTable; private boolean cancelled; private TeaVMProgressListener progressListener; private TeaVM vm; @@ -327,27 +328,31 @@ public class TeaVMTool { try { cancelled = false; log.info("Running TeaVM"); + referenceCache = new ReferenceCache(); TeaVMBuilder vmBuilder = new TeaVMBuilder(prepareTarget()); CacheStatus cacheStatus; - referenceCache = new ReferenceCache(); vmBuilder.setReferenceCache(referenceCache); if (incremental) { cacheDirectory.mkdirs(); symbolTable = new FileSymbolTable(new File(cacheDirectory, "symbols")); fileTable = new FileSymbolTable(new File(cacheDirectory, "files")); + variableTable = new FileSymbolTable(new File(cacheDirectory, "variables")); ClasspathClassHolderSource innerClassSource = new ClasspathClassHolderSource(classLoader, referenceCache); ClassHolderSource classSource = new PreOptimizingClassHolderSource(innerClassSource); cachedClassSource = new DiskCachedClassHolderSource(cacheDirectory, referenceCache, symbolTable, - fileTable, classSource, innerClassSource); - programCache = new DiskProgramCache(cacheDirectory, referenceCache, symbolTable, fileTable); + fileTable, variableTable, classSource, innerClassSource); + programCache = new DiskProgramCache(cacheDirectory, referenceCache, symbolTable, fileTable, + variableTable); if (incremental && targetType == TeaVMTargetType.JAVASCRIPT) { - astCache = new DiskMethodNodeCache(cacheDirectory, referenceCache, symbolTable, fileTable); + astCache = new DiskMethodNodeCache(cacheDirectory, referenceCache, symbolTable, fileTable, + variableTable); javaScriptTarget.setAstCache(astCache); } try { symbolTable.update(); fileTable.update(); + variableTable.update(); } catch (IOException e) { log.info("Cache is missing"); } @@ -420,13 +425,14 @@ public class TeaVMTool { } if (incremental) { - programCache.flush(vm.getDependencyClassSource()); + programCache.flush(); if (astCache != null) { astCache.flush(); } cachedClassSource.flush(); symbolTable.flush(); fileTable.flush(); + variableTable.flush(); log.info("Cache updated"); } diff --git a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java index 89a65d7b9..e8b56af6c 100644 --- a/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java +++ b/tools/devserver/src/main/java/org/teavm/devserver/CodeServlet.java @@ -140,6 +140,7 @@ public class CodeServlet extends HttpServlet { private WebSocketClient wsClient = new WebSocketClient(); private InMemorySymbolTable symbolTable = new InMemorySymbolTable(); private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable(); + private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable(); private ReferenceCache referenceCache = new ReferenceCache(); public CodeServlet(String mainClass, String[] classPath) { @@ -709,8 +710,8 @@ public class CodeServlet extends HttpServlet { watcher = new FileSystemWatcher(classPath); classSource = new MemoryCachedClassReaderSource(); - astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable); - programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable); + astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable); + programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable); } private void shutdownBuilder() {