Decrease memory consumption during compilation

This commit is contained in:
Alexey Andreev 2019-03-06 16:51:01 +03:00
parent 2a1aca98da
commit 88dca1bd02
22 changed files with 412 additions and 182 deletions

View File

@ -17,13 +17,23 @@ package org.teavm.backend.javascript.codegen;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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 { 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 AliasProvider aliasProvider;
private final ClassReaderSource classSource; private final ClassReaderSource classSource;
private final Map<String, String> aliases = new HashMap<>(); private final Map<MethodDescriptor, String> aliases = new HashMap<>();
private final Map<String, ScopedName> privateAliases = new HashMap<>(); private final Map<Key, ScopedName> privateAliases = new HashMap<>();
private final Map<String, ScopedName> classAliases = new HashMap<>(); private final Map<String, ScopedName> classAliases = new HashMap<>();
private final Map<FieldReference, String> fieldAliases = new HashMap<>(); private final Map<FieldReference, String> fieldAliases = new HashMap<>();
private final Map<FieldReference, ScopedName> staticFieldAliases = new HashMap<>(); private final Map<FieldReference, ScopedName> staticFieldAliases = new HashMap<>();
@ -43,35 +53,33 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override @Override
public String getNameFor(MethodDescriptor method) { public String getNameFor(MethodDescriptor method) {
String key = method.toString(); String alias = aliases.get(method);
String alias = aliases.get(key);
if (alias == null) { if (alias == null) {
alias = aliasProvider.getMethodAlias(method); alias = aliasProvider.getMethodAlias(method);
aliases.put(key, alias); aliases.put(method, alias);
} }
return alias; return alias;
} }
@Override @Override
public ScopedName getFullNameFor(MethodReference method) { public ScopedName getFullNameFor(MethodReference method) {
return getFullNameFor(method, 'M'); return getFullNameFor(method, NO_CLASSIFIER);
} }
@Override @Override
public ScopedName getNameForInit(MethodReference method) { 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; MethodReference originalMethod = method;
method = getRealMethod(method); method = getRealMethod(method);
if (method == null) { if (method == null) {
method = originalMethod; method = originalMethod;
} }
MethodReference resolvedMethod = method; return privateAliases.computeIfAbsent(new Key(classifier, method),
return privateAliases.computeIfAbsent(classifier + method.toString(), key -> aliasProvider.getStaticMethodAlias(key.data));
key -> aliasProvider.getStaticMethodAlias(resolvedMethod));
} }
@Override @Override
@ -155,4 +163,38 @@ public class DefaultNamingStrategy implements NamingStrategy {
} }
return fieldRef; 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;
}
}
} }

View File

@ -20,6 +20,7 @@ import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.teavm.ast.ArrayType; import org.teavm.ast.ArrayType;
import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AssignmentStatement;
@ -82,16 +83,22 @@ public class AstIO {
private static final UnaryOperation[] unaryOperations = UnaryOperation.values(); private static final UnaryOperation[] unaryOperations = UnaryOperation.values();
private final SymbolTable symbolTable; private final SymbolTable symbolTable;
private final SymbolTable fileTable; private final SymbolTable fileTable;
private final SymbolTable variableTable;
private final Map<String, IdentifiedStatement> statementMap = new HashMap<>(); private final Map<String, IdentifiedStatement> statementMap = new HashMap<>();
private ReferenceCache referenceCache; 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.referenceCache = referenceCache;
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.fileTable = fileTable; this.fileTable = fileTable;
this.variableTable = variableTable;
} }
public void write(VarDataOutput output, ControlFlowEntry[] cfg) throws IOException { public void write(VarDataOutput output, ControlFlowEntry[] cfg) throws IOException {
lastWrittenLocation = null;
output.writeUnsigned(cfg.length); output.writeUnsigned(cfg.length);
for (ControlFlowEntry entry : cfg) { for (ControlFlowEntry entry : cfg) {
writeLocation(output, entry.from); writeLocation(output, entry.from);
@ -118,10 +125,11 @@ public class AstIO {
private void write(VarDataOutput output, VariableNode variable) throws IOException { private void write(VarDataOutput output, VariableNode variable) throws IOException {
output.writeUnsigned(variable.getIndex()); output.writeUnsigned(variable.getIndex());
output.writeUnsigned(variable.getType().ordinal()); 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 { public ControlFlowEntry[] readControlFlow(VarDataInput input) throws IOException {
lastReadLocation = null;
int size = input.readUnsigned(); int size = input.readUnsigned();
ControlFlowEntry[] result = new ControlFlowEntry[size]; ControlFlowEntry[] result = new ControlFlowEntry[size];
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
@ -143,6 +151,7 @@ public class AstIO {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
node.getVariables().add(readVariable(input)); node.getVariables().add(readVariable(input));
} }
lastReadLocation = null;
node.setBody(readStatement(input)); node.setBody(readStatement(input));
return node; return node;
} }
@ -151,7 +160,8 @@ public class AstIO {
int index = input.readUnsigned(); int index = input.readUnsigned();
VariableType type = VariableType.values()[input.readUnsigned()]; VariableType type = VariableType.values()[input.readUnsigned()];
VariableNode variable = new VariableNode(index, type); 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; return variable;
} }
@ -163,8 +173,9 @@ public class AstIO {
} }
try { try {
output.writeUnsigned(method.getBody().size()); output.writeUnsigned(method.getBody().size());
NodeWriter writer = new NodeWriter(output);
for (int i = 0; i < method.getBody().size(); ++i) { for (int i = 0; i < method.getBody().size(); ++i) {
method.getBody().get(i).getStatement().acceptVisitor(new NodeWriter(output)); method.getBody().get(i).getStatement().acceptVisitor(writer);
} }
} catch (IOExceptionWrapper e) { } catch (IOExceptionWrapper e) {
throw new IOException("Error writing method body", e.getCause()); throw new IOException("Error writing method body", e.getCause());
@ -179,6 +190,7 @@ public class AstIO {
node.getVariables().add(readVariable(input)); node.getVariables().add(readVariable(input));
} }
int partCount = input.readUnsigned(); int partCount = input.readUnsigned();
lastReadLocation = null;
for (int i = 0; i < partCount; ++i) { for (int i = 0; i < partCount; ++i) {
AsyncMethodPart part = new AsyncMethodPart(); AsyncMethodPart part = new AsyncMethodPart();
part.setStatement(readStatement(input)); part.setStatement(readStatement(input));
@ -200,14 +212,21 @@ public class AstIO {
private void writeLocation(VarDataOutput output, TextLocation location) throws IOException { private void writeLocation(VarDataOutput output, TextLocation location) throws IOException {
if (location == null || location.getFileName() == null) { if (location == null || location.getFileName() == null) {
output.writeUnsigned(0); 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 { } else {
output.writeUnsigned(fileTable.lookup(location.getFileName()) + 1); output.writeUnsigned(fileTable.lookup(location.getFileName()) + 2);
output.writeUnsigned(location.getLine()); output.writeUnsigned(location.getLine());
lastWrittenLocation = location;
} }
} }
private class NodeWriter implements ExprVisitor, StatementVisitor { private class NodeWriter implements ExprVisitor, StatementVisitor {
private final VarDataOutput output; private final VarDataOutput output;
private TextLocation lastLocation;
NodeWriter(VarDataOutput output) { NodeWriter(VarDataOutput output) {
super(); super();
@ -220,7 +239,22 @@ public class AstIO {
} }
private void writeLocation(TextLocation location) throws IOException { 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<Statement> sequence) throws IOException { private void writeSequence(List<Statement> sequence) throws IOException {
@ -233,8 +267,8 @@ public class AstIO {
@Override @Override
public void visit(AssignmentStatement statement) { public void visit(AssignmentStatement statement) {
try { try {
output.writeUnsigned(statement.getLeftValue() != null ? 0 : 1);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(statement.getLeftValue() != null ? 0 : 1);
if (statement.getLeftValue() != null) { if (statement.getLeftValue() != null) {
writeExpr(statement.getLeftValue()); writeExpr(statement.getLeftValue());
} }
@ -316,8 +350,8 @@ public class AstIO {
@Override @Override
public void visit(BreakStatement statement) { public void visit(BreakStatement statement) {
try { try {
output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9);
if (statement.getTarget() != null && statement.getTarget().getId() != null) { if (statement.getTarget() != null && statement.getTarget().getId() != null) {
output.write(statement.getTarget().getId()); output.write(statement.getTarget().getId());
} }
@ -329,8 +363,8 @@ public class AstIO {
@Override @Override
public void visit(ContinueStatement statement) { public void visit(ContinueStatement statement) {
try { try {
output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11);
if (statement.getTarget() != null && statement.getTarget().getId() != null) { if (statement.getTarget() != null && statement.getTarget().getId() != null) {
output.write(statement.getTarget().getId()); output.write(statement.getTarget().getId());
} }
@ -342,8 +376,8 @@ public class AstIO {
@Override @Override
public void visit(ReturnStatement statement) { public void visit(ReturnStatement statement) {
try { try {
output.writeUnsigned(statement.getResult() != null ? 12 : 13);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(statement.getResult() != null ? 12 : 13);
if (statement.getResult() != null) { if (statement.getResult() != null) {
writeExpr(statement.getResult()); writeExpr(statement.getResult());
} }
@ -355,8 +389,8 @@ public class AstIO {
@Override @Override
public void visit(ThrowStatement statement) { public void visit(ThrowStatement statement) {
try { try {
output.writeUnsigned(14);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(14);
writeExpr(statement.getException()); writeExpr(statement.getException());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -366,8 +400,8 @@ public class AstIO {
@Override @Override
public void visit(InitClassStatement statement) { public void visit(InitClassStatement statement) {
try { try {
output.writeUnsigned(15);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(15);
output.writeUnsigned(symbolTable.lookup(statement.getClassName())); output.writeUnsigned(symbolTable.lookup(statement.getClassName()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -402,8 +436,8 @@ public class AstIO {
@Override @Override
public void visit(MonitorEnterStatement statement) { public void visit(MonitorEnterStatement statement) {
try { try {
output.writeUnsigned(18);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(18);
writeExpr(statement.getObjectRef()); writeExpr(statement.getObjectRef());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -413,8 +447,8 @@ public class AstIO {
@Override @Override
public void visit(MonitorExitStatement statement) { public void visit(MonitorExitStatement statement) {
try { try {
output.writeUnsigned(19);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeUnsigned(19);
writeExpr(statement.getObjectRef()); writeExpr(statement.getObjectRef());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -636,18 +670,41 @@ public class AstIO {
private TextLocation readLocation(VarDataInput input) throws IOException { private TextLocation readLocation(VarDataInput input) throws IOException {
int fileIndex = input.readUnsigned(); int fileIndex = input.readUnsigned();
if (fileIndex == 0) { if (fileIndex == 0) {
return null; lastReadLocation = null;
} else if (fileIndex == 1) {
lastReadLocation = new TextLocation(lastReadLocation.getFileName(),
lastReadLocation.getLine() + input.readSigned());
} else { } 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 { private Statement readStatement(VarDataInput input) throws IOException {
int type = input.readUnsigned(); int type = readNodeLocation(input.readUnsigned(), input);
switch (type) { switch (type) {
case 0: { case 0: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setLeftValue(readExpr(input)); stmt.setLeftValue(readExpr(input));
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readUnsigned() != 0); stmt.setAsync(input.readUnsigned() != 0);
@ -655,7 +712,7 @@ public class AstIO {
} }
case 1: { case 1: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readUnsigned() != 0); stmt.setAsync(input.readUnsigned() != 0);
return stmt; return stmt;
@ -721,46 +778,46 @@ public class AstIO {
} }
case 8: { case 8: {
BreakStatement stmt = new BreakStatement(); BreakStatement stmt = new BreakStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setTarget(statementMap.get(input.read())); stmt.setTarget(statementMap.get(input.read()));
return stmt; return stmt;
} }
case 9: { case 9: {
BreakStatement stmt = new BreakStatement(); BreakStatement stmt = new BreakStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
return stmt; return stmt;
} }
case 10: { case 10: {
ContinueStatement stmt = new ContinueStatement(); ContinueStatement stmt = new ContinueStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setTarget(statementMap.get(input.read())); stmt.setTarget(statementMap.get(input.read()));
return stmt; return stmt;
} }
case 11: { case 11: {
ContinueStatement stmt = new ContinueStatement(); ContinueStatement stmt = new ContinueStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
return stmt; return stmt;
} }
case 12: { case 12: {
ReturnStatement stmt = new ReturnStatement(); ReturnStatement stmt = new ReturnStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setResult(readExpr(input)); stmt.setResult(readExpr(input));
return stmt; return stmt;
} }
case 13: { case 13: {
ReturnStatement stmt = new ReturnStatement(); ReturnStatement stmt = new ReturnStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
return stmt; return stmt;
} }
case 14: { case 14: {
ThrowStatement stmt = new ThrowStatement(); ThrowStatement stmt = new ThrowStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setException(readExpr(input)); stmt.setException(readExpr(input));
return stmt; return stmt;
} }
case 15: { case 15: {
InitClassStatement stmt = new InitClassStatement(); InitClassStatement stmt = new InitClassStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setClassName(symbolTable.at(input.readUnsigned())); stmt.setClassName(symbolTable.at(input.readUnsigned()));
return stmt; return stmt;
} }
@ -785,13 +842,13 @@ public class AstIO {
} }
case 18: { case 18: {
MonitorEnterStatement stmt = new MonitorEnterStatement(); MonitorEnterStatement stmt = new MonitorEnterStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setObjectRef(readExpr(input)); stmt.setObjectRef(readExpr(input));
return stmt; return stmt;
} }
case 19: { case 19: {
MonitorExitStatement stmt = new MonitorExitStatement(); MonitorExitStatement stmt = new MonitorExitStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(lastReadLocation);
stmt.setObjectRef(readExpr(input)); stmt.setObjectRef(readExpr(input));
return stmt; return stmt;
} }
@ -808,17 +865,11 @@ public class AstIO {
} }
private Expr readExpr(VarDataInput input) throws IOException { private Expr readExpr(VarDataInput input) throws IOException {
TextLocation location = readLocation(input); int type = readNodeLocation(input.readUnsigned(), input);
Expr expr = readExprWithoutLocation(input);
expr.setLocation(location);
return expr;
}
private Expr readExprWithoutLocation(VarDataInput input) throws IOException {
int type = input.readUnsigned();
switch (type) { switch (type) {
case 0: { case 0: {
BinaryExpr expr = new BinaryExpr(); BinaryExpr expr = new BinaryExpr();
expr.setLocation(lastReadLocation);
expr.setOperation(binaryOperations[input.readUnsigned()]); expr.setOperation(binaryOperations[input.readUnsigned()]);
int valueType = input.readUnsigned(); int valueType = input.readUnsigned();
expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null);
@ -828,6 +879,7 @@ public class AstIO {
} }
case 1: { case 1: {
UnaryExpr expr = new UnaryExpr(); UnaryExpr expr = new UnaryExpr();
expr.setLocation(lastReadLocation);
expr.setOperation(unaryOperations[input.readUnsigned()]); expr.setOperation(unaryOperations[input.readUnsigned()]);
int valueType = input.readUnsigned(); int valueType = input.readUnsigned();
expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null);
@ -836,16 +888,20 @@ public class AstIO {
} }
case 2: { case 2: {
ConditionalExpr expr = new ConditionalExpr(); ConditionalExpr expr = new ConditionalExpr();
expr.setLocation(lastReadLocation);
expr.setCondition(readExpr(input)); expr.setCondition(readExpr(input));
expr.setConsequent(readExpr(input)); expr.setConsequent(readExpr(input));
expr.setAlternative(readExpr(input)); expr.setAlternative(readExpr(input));
return expr; return expr;
} }
case 3: { case 3: {
return new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
return expr;
} }
case 4: { case 4: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
expr.setValue(input.readSigned()); expr.setValue(input.readSigned());
return expr; return expr;
} }
@ -856,31 +912,37 @@ public class AstIO {
} }
case 6: { case 6: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
expr.setValue(input.readFloat()); expr.setValue(input.readFloat());
return expr; return expr;
} }
case 7: { case 7: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
expr.setValue(input.readDouble()); expr.setValue(input.readDouble());
return expr; return expr;
} }
case 8: { case 8: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
expr.setValue(input.read()); expr.setValue(input.read());
return expr; return expr;
} }
case 9: { case 9: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setLocation(lastReadLocation);
expr.setValue(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setValue(ValueType.parse(symbolTable.at(input.readUnsigned())));
return expr; return expr;
} }
case 10: { case 10: {
VariableExpr expr = new VariableExpr(); VariableExpr expr = new VariableExpr();
expr.setLocation(lastReadLocation);
expr.setIndex(input.readUnsigned()); expr.setIndex(input.readUnsigned());
return expr; return expr;
} }
case 11: { case 11: {
SubscriptExpr expr = new SubscriptExpr(); SubscriptExpr expr = new SubscriptExpr();
expr.setLocation(lastReadLocation);
expr.setArray(readExpr(input)); expr.setArray(readExpr(input));
expr.setIndex(readExpr(input)); expr.setIndex(readExpr(input));
expr.setType(ArrayType.values()[input.readUnsigned()]); expr.setType(ArrayType.values()[input.readUnsigned()]);
@ -888,6 +950,7 @@ public class AstIO {
} }
case 12: { case 12: {
UnwrapArrayExpr expr = new UnwrapArrayExpr(ArrayType.values()[input.readUnsigned()]); UnwrapArrayExpr expr = new UnwrapArrayExpr(ArrayType.values()[input.readUnsigned()]);
expr.setLocation(lastReadLocation);
expr.setArray(readExpr(input)); expr.setArray(readExpr(input));
return expr; return expr;
} }
@ -901,6 +964,7 @@ public class AstIO {
return parseInvocationExpr(InvocationType.DYNAMIC, input); return parseInvocationExpr(InvocationType.DYNAMIC, input);
case 17: { case 17: {
QualificationExpr expr = new QualificationExpr(); QualificationExpr expr = new QualificationExpr();
expr.setLocation(lastReadLocation);
String className = symbolTable.at(input.readUnsigned()); String className = symbolTable.at(input.readUnsigned());
String fieldName = symbolTable.at(input.readUnsigned()); String fieldName = symbolTable.at(input.readUnsigned());
expr.setField(new FieldReference(className, fieldName)); expr.setField(new FieldReference(className, fieldName));
@ -908,6 +972,7 @@ public class AstIO {
} }
case 18: { case 18: {
QualificationExpr expr = new QualificationExpr(); QualificationExpr expr = new QualificationExpr();
expr.setLocation(lastReadLocation);
expr.setQualified(readExpr(input)); expr.setQualified(readExpr(input));
String className = symbolTable.at(input.readUnsigned()); String className = symbolTable.at(input.readUnsigned());
String fieldName = symbolTable.at(input.readUnsigned()); String fieldName = symbolTable.at(input.readUnsigned());
@ -916,17 +981,20 @@ public class AstIO {
} }
case 19: { case 19: {
NewExpr expr = new NewExpr(); NewExpr expr = new NewExpr();
expr.setLocation(lastReadLocation);
expr.setConstructedClass(symbolTable.at(input.readUnsigned())); expr.setConstructedClass(symbolTable.at(input.readUnsigned()));
return expr; return expr;
} }
case 20: { case 20: {
NewArrayExpr expr = new NewArrayExpr(); NewArrayExpr expr = new NewArrayExpr();
expr.setLocation(lastReadLocation);
expr.setLength(readExpr(input)); expr.setLength(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
return expr; return expr;
} }
case 21: { case 21: {
NewMultiArrayExpr expr = new NewMultiArrayExpr(); NewMultiArrayExpr expr = new NewMultiArrayExpr();
expr.setLocation(lastReadLocation);
int dimensionCount = input.readUnsigned(); int dimensionCount = input.readUnsigned();
for (int i = 0; i < dimensionCount; ++i) { for (int i = 0; i < dimensionCount; ++i) {
expr.getDimensions().add(readExpr(input)); expr.getDimensions().add(readExpr(input));
@ -936,18 +1004,21 @@ public class AstIO {
} }
case 22: { case 22: {
InstanceOfExpr expr = new InstanceOfExpr(); InstanceOfExpr expr = new InstanceOfExpr();
expr.setLocation(lastReadLocation);
expr.setExpr(readExpr(input)); expr.setExpr(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
return expr; return expr;
} }
case 23: { case 23: {
CastExpr expr = new CastExpr(); CastExpr expr = new CastExpr();
expr.setLocation(lastReadLocation);
expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned()))); expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned())));
expr.setValue(readExpr(input)); expr.setValue(readExpr(input));
return expr; return expr;
} }
case 24: { case 24: {
PrimitiveCastExpr expr = new PrimitiveCastExpr(); PrimitiveCastExpr expr = new PrimitiveCastExpr();
expr.setLocation(lastReadLocation);
expr.setSource(OperationType.values()[input.readUnsigned()]); expr.setSource(OperationType.values()[input.readUnsigned()]);
expr.setTarget(OperationType.values()[input.readUnsigned()]); expr.setTarget(OperationType.values()[input.readUnsigned()]);
expr.setValue(readExpr(input)); expr.setValue(readExpr(input));
@ -960,6 +1031,7 @@ public class AstIO {
private InvocationExpr parseInvocationExpr(InvocationType invocationType, VarDataInput input) throws IOException { private InvocationExpr parseInvocationExpr(InvocationType invocationType, VarDataInput input) throws IOException {
InvocationExpr expr = new InvocationExpr(); InvocationExpr expr = new InvocationExpr();
expr.setLocation(lastReadLocation);
expr.setType(invocationType); expr.setType(invocationType);
String className = symbolTable.at(input.readUnsigned()); String className = symbolTable.at(input.readUnsigned());
String signature = symbolTable.at(input.readUnsigned()); String signature = symbolTable.at(input.readUnsigned());

View File

@ -64,12 +64,13 @@ public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStat
private ProgramIO programIO; private ProgramIO programIO;
public DiskCachedClassHolderSource(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, 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.directory = directory;
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.innerSource = innerSource; this.innerSource = innerSource;
this.classDateProvider = classDateProvider; this.classDateProvider = classDateProvider;
programIO = new ProgramIO(referenceCache, symbolTable, fileTable); programIO = new ProgramIO(referenceCache, symbolTable, fileTable, variableTable);
} }
@Override @Override

View File

@ -42,9 +42,9 @@ public class DiskMethodNodeCache implements MethodNodeCache {
private final Set<MethodReference> newAsyncMethods = new HashSet<>(); private final Set<MethodReference> newAsyncMethods = new HashSet<>();
public DiskMethodNodeCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, public DiskMethodNodeCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable,
SymbolTable fileTable) { SymbolTable fileTable, SymbolTable variableTable) {
this.directory = directory; this.directory = directory;
astIO = new AstIO(referenceCache, symbolTable, fileTable); astIO = new AstIO(referenceCache, symbolTable, fileTable, variableTable);
} }
@Override @Override

View File

@ -27,13 +27,11 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ProgramCache; import org.teavm.model.ProgramCache;
@ -46,9 +44,9 @@ public class DiskProgramCache implements ProgramCache {
private Set<MethodReference> newMethods = new HashSet<>(); private Set<MethodReference> newMethods = new HashSet<>();
public DiskProgramCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable, public DiskProgramCache(File directory, ReferenceCache referenceCache, SymbolTable symbolTable,
SymbolTable fileTable) { SymbolTable fileTable, SymbolTable variableTable) {
this.directory = directory; this.directory = directory;
programIO = new ProgramIO(referenceCache, symbolTable, fileTable); programIO = new ProgramIO(referenceCache, symbolTable, fileTable, variableTable);
} }
@Override @Override
@ -90,8 +88,7 @@ public class DiskProgramCache implements ProgramCache {
newMethods.add(method); newMethods.add(method);
} }
public void flush(ClassReaderSource classSource) throws IOException { public void flush() throws IOException {
Date currentTime = new Date();
for (MethodReference method : newMethods) { for (MethodReference method : newMethods) {
Item item = cache.get(method); Item item = cache.get(method);
File file = getMethodFile(method); File file = getMethodFile(method);

View File

@ -36,8 +36,8 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
private AstIO io; private AstIO io;
public InMemoryMethodNodeCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable, public InMemoryMethodNodeCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable,
InMemorySymbolTable fileSymbolTable) { InMemorySymbolTable fileSymbolTable, InMemorySymbolTable variableSymbolTable) {
io = new AstIO(referenceCache, symbolTable, fileSymbolTable); io = new AstIO(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
} }
@Override @Override

View File

@ -33,8 +33,8 @@ public class InMemoryProgramCache implements ProgramCache {
private ProgramIO io; private ProgramIO io;
public InMemoryProgramCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable, public InMemoryProgramCache(ReferenceCache referenceCache, InMemorySymbolTable symbolTable,
InMemorySymbolTable fileSymbolTable) { InMemorySymbolTable fileSymbolTable, InMemorySymbolTable variableSymbolTable) {
io = new ProgramIO(referenceCache, symbolTable, fileSymbolTable); io = new ProgramIO(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
} }
@Override @Override

View File

@ -85,6 +85,7 @@ import org.teavm.model.instructions.UnwrapArrayInstruction;
public class ProgramIO { public class ProgramIO {
private SymbolTable symbolTable; private SymbolTable symbolTable;
private SymbolTable fileTable; private SymbolTable fileTable;
private SymbolTable variableTable;
private ReferenceCache referenceCache; private ReferenceCache referenceCache;
private static BinaryOperation[] binaryOperations = BinaryOperation.values(); private static BinaryOperation[] binaryOperations = BinaryOperation.values();
private static NumericOperandType[] numericOperandTypes = NumericOperandType.values(); private static NumericOperandType[] numericOperandTypes = NumericOperandType.values();
@ -94,10 +95,12 @@ public class ProgramIO {
private static BinaryBranchingCondition[] binaryBranchingConditions = BinaryBranchingCondition.values(); private static BinaryBranchingCondition[] binaryBranchingConditions = BinaryBranchingCondition.values();
private static ArrayElementType[] arrayElementTypes = ArrayElementType.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.referenceCache = referenceCache;
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.fileTable = fileTable; this.fileTable = fileTable;
this.variableTable = variableTable;
} }
public void write(Program program, OutputStream output) throws IOException { public void write(Program program, OutputStream output) throws IOException {
@ -107,7 +110,7 @@ public class ProgramIO {
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
Variable var = program.variableAt(i); Variable var = program.variableAt(i);
data.writeUnsigned(var.getRegister()); 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) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock basicBlock = program.basicBlockAt(i); BasicBlock basicBlock = program.basicBlockAt(i);
@ -133,13 +136,20 @@ public class ProgramIO {
for (Instruction insn : basicBlock) { for (Instruction insn : basicBlock) {
try { try {
if (!Objects.equals(location, insn.getLocation())) { if (!Objects.equals(location, insn.getLocation())) {
location = insn.getLocation(); TextLocation newLocation = insn.getLocation();
if (location == null || location.getFileName() == null || location.getLine() < 0) { if (newLocation == null || newLocation.getFileName() == null || newLocation.getLine() < 0) {
data.writeUnsigned(1); data.writeUnsigned(1);
location = null;
} else {
if (location != null && location.getFileName().equals(newLocation.getFileName())) {
data.writeUnsigned(127);
data.writeSigned(newLocation.getLine() - location.getLine());
} else { } else {
data.writeUnsigned(2); data.writeUnsigned(2);
data.writeUnsigned(fileTable.lookup(location.getFileName())); data.writeUnsigned(fileTable.lookup(newLocation.getFileName()));
data.writeUnsigned(location.getLine()); data.writeUnsigned(newLocation.getLine());
}
location = newLocation;
} }
} }
insn.acceptVisitor(insnWriter); insn.acceptVisitor(insnWriter);
@ -159,7 +169,8 @@ public class ProgramIO {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setRegister(data.readUnsigned()); 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) { for (int i = 0; i < basicBlockCount; ++i) {
program.createBasicBlock(); program.createBasicBlock();
@ -212,6 +223,11 @@ public class ProgramIO {
location = new TextLocation(file, line); location = new TextLocation(file, line);
break; break;
} }
case 127: {
int line = location.getLine() + data.readSigned();
location = new TextLocation(location.getFileName(), line);
break;
}
default: { default: {
Instruction insn = readInstruction(insnType, program, data); Instruction insn = readInstruction(insnType, program, data);
insn.setLocation(location); insn.setLocation(location);

View File

@ -69,7 +69,15 @@ public class VarDataInput {
} }
public float readFloat() throws IOException { 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; int mantissa = Integer.reverse(readUnsigned()) >>> 8;
boolean sign = (mantissa & (1 << 23)) != 0; boolean sign = (mantissa & (1 << 23)) != 0;
@ -83,7 +91,15 @@ public class VarDataInput {
} }
public double readDouble() throws IOException { 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; long mantissa = Long.reverse(readUnsignedLong()) >>> 11;
boolean sign = (mantissa & (1L << 52)) != 0; boolean sign = (mantissa & (1L << 52)) != 0;

View File

@ -53,6 +53,10 @@ public class VarDataOutput implements Closeable {
} }
public void writeFloat(float value) throws IOException { public void writeFloat(float value) throws IOException {
if (value == 0) {
writeUnsigned(0);
return;
}
int bits = Float.floatToRawIntBits(value); int bits = Float.floatToRawIntBits(value);
boolean sign = (bits & (1 << 31)) != 0; boolean sign = (bits & (1 << 31)) != 0;
int exponent = (bits >> 23) & ((1 << 8) - 1); int exponent = (bits >> 23) & ((1 << 8) - 1);
@ -60,11 +64,16 @@ public class VarDataOutput implements Closeable {
if (sign) { if (sign) {
mantissa |= 1 << 23; mantissa |= 1 << 23;
} }
writeSigned(exponent - 127); exponent -= 127;
writeUnsigned(1 + (exponent > 0 ? exponent << 1 : 1 | (-exponent << 1)));
writeUnsigned(Integer.reverse(mantissa << 8)); writeUnsigned(Integer.reverse(mantissa << 8));
} }
public void writeDouble(double value) throws IOException { public void writeDouble(double value) throws IOException {
if (value == 0) {
writeUnsigned(0);
return;
}
long bits = Double.doubleToRawLongBits(value); long bits = Double.doubleToRawLongBits(value);
boolean sign = (bits & (1L << 63)) != 0; boolean sign = (bits & (1L << 63)) != 0;
int exponent = (int) (bits >> 52) & ((1 << 11) - 1); int exponent = (int) (bits >> 52) & ((1 << 11) - 1);
@ -72,7 +81,8 @@ public class VarDataOutput implements Closeable {
if (sign) { if (sign) {
mantissa |= 1L << 52; mantissa |= 1L << 52;
} }
writeSigned(exponent - 1023); exponent -= 1023;
writeUnsigned(1 + (exponent > 0 ? exponent << 1 : 1 | (-exponent << 1)));
writeUnsigned(Long.reverse(mantissa << 11)); writeUnsigned(Long.reverse(mantissa << 11));
} }

View File

@ -53,6 +53,10 @@ public class DebugInformation {
MethodTree methodTree; MethodTree methodTree;
ReferenceCache referenceCache; ReferenceCache referenceCache;
public DebugInformation() {
this(new ReferenceCache());
}
public DebugInformation(ReferenceCache referenceCache) { public DebugInformation(ReferenceCache referenceCache) {
this.referenceCache = referenceCache; this.referenceCache = referenceCache;
} }

View File

@ -26,7 +26,6 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Deque; import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -37,7 +36,6 @@ import org.objectweb.asm.tree.ClassNode;
import org.teavm.cache.IncrementalDependencyProvider; import org.teavm.cache.IncrementalDependencyProvider;
import org.teavm.cache.IncrementalDependencyRegistration; import org.teavm.cache.IncrementalDependencyRegistration;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.callgraph.CallGraphNode;
import org.teavm.callgraph.DefaultCallGraph; import org.teavm.callgraph.DefaultCallGraph;
import org.teavm.common.CachedMapper; import org.teavm.common.CachedMapper;
import org.teavm.common.Mapper; import org.teavm.common.Mapper;
@ -429,8 +427,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
private ClassDependency createClassDependency(String className) { private ClassDependency createClassDependency(String className) {
ClassReader cls = classSource.get(className); ClassReader cls = classSource.get(className);
ClassDependency dependency = new ClassDependency(this, className, cls); return new ClassDependency(this, className, cls);
return dependency;
} }
public MethodDependency linkMethod(String className, MethodDescriptor descriptor) { public MethodDependency linkMethod(String className, MethodDescriptor descriptor) {
@ -527,8 +524,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
return classCache.getCachedPreimages(); return classCache.getCachedPreimages();
} }
private Set<FieldReference> fieldsAddedByRoot = new HashSet<>();
public FieldDependency linkField(FieldReference fieldRef) { public FieldDependency linkField(FieldReference fieldRef) {
FieldDependency dep = fieldCache.map(fieldRef); FieldDependency dep = fieldCache.map(fieldRef);
if (!dep.activated) { if (!dep.activated) {
@ -746,9 +741,25 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
} }
} }
for (Map<?, MethodDependency> 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(); allNodes.clear();
classSource.cleanup(); classSource.cleanup();
agent.cleanup(); agent.cleanup();
listeners.clear();
} }
public void cleanupTypes() { public void cleanupTypes() {
@ -857,10 +868,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
return; return;
} }
CallGraphNode caller = callGraph.getNode(methodDep.getReference());
ProgramEmitter pe = ProgramEmitter.create(program, classHierarchy); ProgramEmitter pe = ProgramEmitter.create(program, classHierarchy);
boolean hasIndy = false;
BasicBlockSplitter splitter = new BasicBlockSplitter(program); BasicBlockSplitter splitter = new BasicBlockSplitter(program);
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
@ -885,7 +893,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
continue; continue;
} }
hasIndy = true;
BasicBlock splitBlock = splitter.split(block, insn); BasicBlock splitBlock = splitter.split(block, insn);
pe.enter(block); pe.enter(block);
@ -910,7 +917,6 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
pe.addInstruction(assign); pe.addInstruction(assign);
} }
pe.jump(splitBlock); pe.jump(splitBlock);
block = splitBlock;
} }
} }
splitter.fixProgram(); splitter.fixProgram();

View File

@ -189,4 +189,11 @@ public class FastDependencyAnalyzer extends DependencyAnalyzer {
boolean domainOptimizationEnabled() { boolean domainOptimizationEnabled() {
return false; return false;
} }
@Override
public void cleanup() {
virtualCallConsumers.clear();
subtypeNodes.clear();
super.cleanup();
}
} }

View File

@ -28,8 +28,8 @@ public class FieldDependency implements FieldDependencyInfo {
DependencyNode value; DependencyNode value;
private FieldReader field; private FieldReader field;
private FieldReference reference; private FieldReference reference;
private List<LocationListener> locationListeners; List<LocationListener> locationListeners;
private Set<CallLocation> locations; Set<CallLocation> locations;
boolean activated; boolean activated;
FieldDependency(DependencyNode value, FieldReader field, FieldReference reference) { FieldDependency(DependencyNode value, FieldReader field, FieldReference reference) {

View File

@ -38,8 +38,8 @@ public class MethodDependency implements MethodDependencyInfo {
boolean external; boolean external;
DependencyPlugin dependencyPlugin; DependencyPlugin dependencyPlugin;
boolean dependencyPluginAttached; boolean dependencyPluginAttached;
private List<LocationListener> locationListeners; List<LocationListener> locationListeners;
private Set<CallLocation> locations; Set<CallLocation> locations;
boolean activated; boolean activated;
MethodDependency(DependencyAnalyzer dependencyAnalyzer, DependencyNode[] variableNodes, int parameterCount, MethodDependency(DependencyAnalyzer dependencyAnalyzer, DependencyNode[] variableNodes, int parameterCount,

View File

@ -20,7 +20,7 @@ import java.util.Arrays;
public class MethodDescriptor { public class MethodDescriptor {
private String name; private String name;
private ValueType[] signature; private ValueType[] signature;
private volatile String reprCache; private int hash;
public MethodDescriptor(String name, ValueType... signature) { public MethodDescriptor(String name, ValueType... signature) {
if (signature.length < 1) { if (signature.length < 1) {
@ -70,10 +70,7 @@ public class MethodDescriptor {
@Override @Override
public String toString() { public String toString() {
if (reprCache == null) { return name + signatureToString();
reprCache = name + signatureToString();
}
return reprCache;
} }
public String signatureToString() { public String signatureToString() {
@ -140,7 +137,17 @@ public class MethodDescriptor {
@Override @Override
public int hashCode() { 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 @Override
@ -151,6 +158,22 @@ public class MethodDescriptor {
if (!(obj instanceof MethodDescriptor)) { if (!(obj instanceof MethodDescriptor)) {
return false; return false;
} }
return toString().equals(obj.toString()); 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;
} }
} }

View File

@ -35,16 +35,12 @@ import java.util.stream.Stream;
*/ */
public class MethodReference implements Serializable { public class MethodReference implements Serializable {
private String className; private String className;
private String name;
private ValueType[] signature;
private transient MethodDescriptor descriptor; private transient MethodDescriptor descriptor;
private transient String reprCache; private int hash;
public MethodReference(String className, MethodDescriptor descriptor) { public MethodReference(String className, MethodDescriptor descriptor) {
this.className = className; this.className = className;
this.descriptor = descriptor; 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. * a type of a returning value, and all the remaining elements are types of arguments.
*/ */
public MethodReference(String className, String name, ValueType... signature) { public MethodReference(String className, String name, ValueType... signature) {
this.className = className; this(className, new MethodDescriptor(name, signature));
this.name = name;
this.signature = Arrays.copyOf(signature, signature.length);
} }
public MethodReference(Class<?> cls, String name, Class<?>... signature) { public MethodReference(Class<?> cls, String name, Class<?>... signature) {
@ -86,42 +80,42 @@ public class MethodReference implements Serializable {
} }
public MethodDescriptor getDescriptor() { public MethodDescriptor getDescriptor() {
if (descriptor == null) {
descriptor = new MethodDescriptor(name, signature);
}
return descriptor; return descriptor;
} }
public int parameterCount() { public int parameterCount() {
return signature.length - 1; return descriptor.parameterCount();
} }
public ValueType parameterType(int index) { public ValueType parameterType(int index) {
if (index >= signature.length + 1) { return descriptor.parameterType(index);
throw new IndexOutOfBoundsException("Index " + index + " is greater than size " + (signature.length - 1));
}
return signature[index];
} }
public ValueType[] getParameterTypes() { public ValueType[] getParameterTypes() {
return Arrays.copyOf(signature, signature.length - 1); return descriptor.getParameterTypes();
} }
public ValueType[] getSignature() { public ValueType[] getSignature() {
return Arrays.copyOf(signature, signature.length); return descriptor.getSignature();
} }
public ValueType getReturnType() { public ValueType getReturnType() {
return signature[signature.length - 1]; return descriptor.getResultType();
} }
public String getName() { public String getName() {
return name; return descriptor.getName();
} }
@Override @Override
public int hashCode() { public int hashCode() {
return toString().hashCode(); if (hash == 0) {
hash = (className.hashCode() * 31 + descriptor.hashCode()) * 17;
if (hash == 0) {
hash++;
}
}
return hash;
} }
@Override @Override
@ -132,17 +126,15 @@ public class MethodReference implements Serializable {
if (!(obj instanceof MethodReference)) { if (!(obj instanceof MethodReference)) {
return false; return false;
} }
MethodReference other = (MethodReference) obj; MethodReference other = (MethodReference) obj;
return toString().equals(other.toString()); return className.equals(other.className) && descriptor.equals(other.descriptor);
} }
@Override @Override
@JsonValue @JsonValue
public String toString() { public String toString() {
if (reprCache == null) { return className + "." + getDescriptor().toString();
reprCache = className + "." + getDescriptor().toString();
}
return reprCache;
} }
@JsonCreator @JsonCreator

View File

@ -20,7 +20,6 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public abstract class ValueType implements Serializable { public abstract class ValueType implements Serializable {
volatile String reprCache;
private static final Map<Class<?>, ValueType> primitiveMap = new HashMap<>(); private static final Map<Class<?>, ValueType> primitiveMap = new HashMap<>();
private ValueType() { private ValueType() {
@ -28,6 +27,7 @@ public abstract class ValueType implements Serializable {
public static class Object extends ValueType { public static class Object extends ValueType {
private String className; private String className;
private int hash;
public Object(String className) { public Object(String className) {
this.className = className; this.className = className;
@ -39,23 +39,45 @@ public abstract class ValueType implements Serializable {
@Override @Override
public String toString() { public String toString() {
if (reprCache == null) { return "L" + className.replace('.', '/') + ";";
reprCache = "L" + className.replace('.', '/') + ";";
}
return reprCache;
} }
@Override @Override
public boolean isObject(String className) { public boolean isObject(String className) {
return this.className.equals(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 { public static class Primitive extends ValueType {
private PrimitiveType kind; private PrimitiveType kind;
private int hash;
Primitive(PrimitiveType kind) { private Primitive(PrimitiveType kind) {
this.kind = kind; this.kind = kind;
hash = 17988782 ^ (kind.ordinal() * 31);
} }
public PrimitiveType getKind() { public PrimitiveType getKind() {
@ -64,13 +86,6 @@ public abstract class ValueType implements Serializable {
@Override @Override
public String toString() { public String toString() {
if (reprCache == null) {
reprCache = createString();
}
return reprCache;
}
private String createString() {
switch (kind) { switch (kind) {
case BOOLEAN: case BOOLEAN:
return "Z"; return "Z";
@ -97,10 +112,21 @@ public abstract class ValueType implements Serializable {
public boolean isObject(String cls) { public boolean isObject(String cls) {
return false; 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 { public static class Array extends ValueType {
private ValueType itemType; private ValueType itemType;
private int hash;
public Array(ValueType itemType) { public Array(ValueType itemType) {
this.itemType = itemType; this.itemType = itemType;
@ -112,19 +138,43 @@ public abstract class ValueType implements Serializable {
@Override @Override
public String toString() { public String toString() {
if (reprCache == null) { return "[" + itemType;
reprCache = "[" + itemType.toString();
}
return reprCache;
} }
@Override @Override
public boolean isObject(String cls) { public boolean isObject(String cls) {
return false; 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 { public static class Void extends ValueType {
private Void() {
}
@Override @Override
public String toString() { public String toString() {
return "V"; return "V";
@ -134,12 +184,15 @@ public abstract class ValueType implements Serializable {
public boolean isObject(String cls) { public boolean isObject(String cls) {
return false; return false;
} }
@Override
public boolean equals(java.lang.Object obj) {
return this == obj;
} }
public static class Null extends ValueType {
@Override @Override
public boolean isObject(String cls) { public int hashCode() {
return false; return 53604390;
} }
} }
@ -161,9 +214,6 @@ public abstract class ValueType implements Serializable {
public static final Primitive CHARACTER = new Primitive(PrimitiveType.CHARACTER); public static final Primitive CHARACTER = new Primitive(PrimitiveType.CHARACTER);
public static final Null NULL = new Null();
static { static {
primitiveMap.put(boolean.class, BOOLEAN); primitiveMap.put(boolean.class, BOOLEAN);
primitiveMap.put(char.class, CHARACTER); primitiveMap.put(char.class, CHARACTER);
@ -227,7 +277,7 @@ public abstract class ValueType implements Serializable {
types.add(type); types.add(type);
index = nextIndex; index = nextIndex;
} }
return types.toArray(new ValueType[types.size()]); return types.toArray(new ValueType[0]);
} }
private static int cut(String text, int index) { private static int cut(String text, int index) {
@ -344,20 +394,4 @@ public abstract class ValueType implements Serializable {
return ValueType.object(cls.getName()); 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());
}
} }

View File

@ -158,7 +158,8 @@ public class ProgramIOTest {
private Program inputOutput(Program program) { private Program inputOutput(Program program) {
InMemorySymbolTable symbolTable = new InMemorySymbolTable(); InMemorySymbolTable symbolTable = new InMemorySymbolTable();
InMemorySymbolTable fileTable = 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()) { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
programIO.write(program, output); programIO.write(program, output);
try (ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray())) { try (ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray())) {

View File

@ -239,7 +239,8 @@ public class IncrementalTest {
boolean capturing; boolean capturing;
CapturingMethodNodeCache() { CapturingMethodNodeCache() {
super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable()); super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable(),
new InMemorySymbolTable());
} }
@Override @Override
@ -264,7 +265,8 @@ public class IncrementalTest {
boolean capturing; boolean capturing;
CapturingProgramCache() { CapturingProgramCache() {
super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable()); super(new ReferenceCache(), new InMemorySymbolTable(), new InMemorySymbolTable(),
new InMemorySymbolTable());
} }
@Override @Override

View File

@ -88,6 +88,7 @@ public class TeaVMTool {
private DiskMethodNodeCache astCache; private DiskMethodNodeCache astCache;
private FileSymbolTable symbolTable; private FileSymbolTable symbolTable;
private FileSymbolTable fileTable; private FileSymbolTable fileTable;
private FileSymbolTable variableTable;
private boolean cancelled; private boolean cancelled;
private TeaVMProgressListener progressListener; private TeaVMProgressListener progressListener;
private TeaVM vm; private TeaVM vm;
@ -327,27 +328,31 @@ public class TeaVMTool {
try { try {
cancelled = false; cancelled = false;
log.info("Running TeaVM"); log.info("Running TeaVM");
referenceCache = new ReferenceCache();
TeaVMBuilder vmBuilder = new TeaVMBuilder(prepareTarget()); TeaVMBuilder vmBuilder = new TeaVMBuilder(prepareTarget());
CacheStatus cacheStatus; CacheStatus cacheStatus;
referenceCache = new ReferenceCache();
vmBuilder.setReferenceCache(referenceCache); vmBuilder.setReferenceCache(referenceCache);
if (incremental) { if (incremental) {
cacheDirectory.mkdirs(); cacheDirectory.mkdirs();
symbolTable = new FileSymbolTable(new File(cacheDirectory, "symbols")); symbolTable = new FileSymbolTable(new File(cacheDirectory, "symbols"));
fileTable = new FileSymbolTable(new File(cacheDirectory, "files")); fileTable = new FileSymbolTable(new File(cacheDirectory, "files"));
variableTable = new FileSymbolTable(new File(cacheDirectory, "variables"));
ClasspathClassHolderSource innerClassSource = new ClasspathClassHolderSource(classLoader, ClasspathClassHolderSource innerClassSource = new ClasspathClassHolderSource(classLoader,
referenceCache); referenceCache);
ClassHolderSource classSource = new PreOptimizingClassHolderSource(innerClassSource); ClassHolderSource classSource = new PreOptimizingClassHolderSource(innerClassSource);
cachedClassSource = new DiskCachedClassHolderSource(cacheDirectory, referenceCache, symbolTable, cachedClassSource = new DiskCachedClassHolderSource(cacheDirectory, referenceCache, symbolTable,
fileTable, classSource, innerClassSource); fileTable, variableTable, classSource, innerClassSource);
programCache = new DiskProgramCache(cacheDirectory, referenceCache, symbolTable, fileTable); programCache = new DiskProgramCache(cacheDirectory, referenceCache, symbolTable, fileTable,
variableTable);
if (incremental && targetType == TeaVMTargetType.JAVASCRIPT) { if (incremental && targetType == TeaVMTargetType.JAVASCRIPT) {
astCache = new DiskMethodNodeCache(cacheDirectory, referenceCache, symbolTable, fileTable); astCache = new DiskMethodNodeCache(cacheDirectory, referenceCache, symbolTable, fileTable,
variableTable);
javaScriptTarget.setAstCache(astCache); javaScriptTarget.setAstCache(astCache);
} }
try { try {
symbolTable.update(); symbolTable.update();
fileTable.update(); fileTable.update();
variableTable.update();
} catch (IOException e) { } catch (IOException e) {
log.info("Cache is missing"); log.info("Cache is missing");
} }
@ -420,13 +425,14 @@ public class TeaVMTool {
} }
if (incremental) { if (incremental) {
programCache.flush(vm.getDependencyClassSource()); programCache.flush();
if (astCache != null) { if (astCache != null) {
astCache.flush(); astCache.flush();
} }
cachedClassSource.flush(); cachedClassSource.flush();
symbolTable.flush(); symbolTable.flush();
fileTable.flush(); fileTable.flush();
variableTable.flush();
log.info("Cache updated"); log.info("Cache updated");
} }

View File

@ -140,6 +140,7 @@ public class CodeServlet extends HttpServlet {
private WebSocketClient wsClient = new WebSocketClient(); private WebSocketClient wsClient = new WebSocketClient();
private InMemorySymbolTable symbolTable = new InMemorySymbolTable(); private InMemorySymbolTable symbolTable = new InMemorySymbolTable();
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable(); private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable();
private ReferenceCache referenceCache = new ReferenceCache(); private ReferenceCache referenceCache = new ReferenceCache();
public CodeServlet(String mainClass, String[] classPath) { public CodeServlet(String mainClass, String[] classPath) {
@ -709,8 +710,8 @@ public class CodeServlet extends HttpServlet {
watcher = new FileSystemWatcher(classPath); watcher = new FileSystemWatcher(classPath);
classSource = new MemoryCachedClassReaderSource(); classSource = new MemoryCachedClassReaderSource();
astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable); astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable); programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
} }
private void shutdownBuilder() { private void shutdownBuilder() {