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.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<String, String> aliases = new HashMap<>();
private final Map<String, ScopedName> privateAliases = new HashMap<>();
private final Map<MethodDescriptor, String> aliases = new HashMap<>();
private final Map<Key, ScopedName> privateAliases = new HashMap<>();
private final Map<String, ScopedName> classAliases = new HashMap<>();
private final Map<FieldReference, String> fieldAliases = new HashMap<>();
private final Map<FieldReference, ScopedName> 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;
}
}
}

View File

@ -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<String, IdentifiedStatement> 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;
}
@ -163,8 +173,9 @@ public class AstIO {
}
try {
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(new NodeWriter(output));
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<Statement> 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());

View File

@ -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

View File

@ -42,9 +42,9 @@ public class DiskMethodNodeCache implements MethodNodeCache {
private final Set<MethodReference> 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

View File

@ -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<MethodReference> 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);

View File

@ -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

View File

@ -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

View File

@ -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 {
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(location.getFileName()));
data.writeUnsigned(location.getLine());
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);

View File

@ -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;

View File

@ -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));
}

View File

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

View File

@ -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<FieldReference> 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<?, 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();
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();

View File

@ -189,4 +189,11 @@ public class FastDependencyAnalyzer extends DependencyAnalyzer {
boolean domainOptimizationEnabled() {
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;
private FieldReader field;
private FieldReference reference;
private List<LocationListener> locationListeners;
private Set<CallLocation> locations;
List<LocationListener> locationListeners;
Set<CallLocation> locations;
boolean activated;
FieldDependency(DependencyNode value, FieldReader field, FieldReference reference) {

View File

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

View File

@ -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,7 +137,17 @@ 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
@ -151,6 +158,22 @@ public class MethodDescriptor {
if (!(obj instanceof MethodDescriptor)) {
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 {
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

View File

@ -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<Class<?>, 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;
}
@Override
public boolean equals(java.lang.Object obj) {
return this == obj;
}
public static class Null extends ValueType {
@Override
public boolean isObject(String cls) {
return false;
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());
}
}

View File

@ -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())) {

View File

@ -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

View File

@ -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");
}

View File

@ -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() {