Store AST cash in binary format. Introduce more compact

AST serialization format.

Reduce memory consumption of incremental compilation on dev server
This commit is contained in:
Alexey Andreev 2019-03-05 19:06:21 +03:00
parent 573c5f6064
commit 3c9a3bb359
10 changed files with 280 additions and 246 deletions

View File

@ -15,8 +15,6 @@
*/ */
package org.teavm.cache; package org.teavm.cache;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
@ -73,6 +71,7 @@ import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ReferenceCache;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.util.VariableType; import org.teavm.model.util.VariableType;
@ -84,34 +83,27 @@ public class AstIO {
private final SymbolTable symbolTable; private final SymbolTable symbolTable;
private final SymbolTable fileTable; private final SymbolTable fileTable;
private final Map<String, IdentifiedStatement> statementMap = new HashMap<>(); private final Map<String, IdentifiedStatement> statementMap = new HashMap<>();
private Map<String, MethodDescriptor> methodDescriptorCache = new HashMap<>(); private ReferenceCache referenceCache = new ReferenceCache();
private Map<String, Map<MethodDescriptor, MethodReference>> methodReferenceCache = new HashMap<>();
public AstIO(SymbolTable symbolTable, SymbolTable fileTable) { public AstIO(SymbolTable symbolTable, SymbolTable fileTable) {
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.fileTable = fileTable; this.fileTable = fileTable;
} }
public void write(DataOutput output, ControlFlowEntry[] cfg) throws IOException { public void write(VarDataOutput output, ControlFlowEntry[] cfg) throws IOException {
output.writeShort(cfg.length); output.writeUnsigned(cfg.length);
for (ControlFlowEntry entry : cfg) { for (ControlFlowEntry entry : cfg) {
writeLocation(output, entry.from); writeLocation(output, entry.from);
output.writeShort(entry.to.length); output.writeUnsigned(entry.to.length);
for (TextLocation loc : entry.to) { for (TextLocation loc : entry.to) {
if (loc != null) {
output.writeByte(1);
writeLocation(output, loc); writeLocation(output, loc);
} else {
output.writeByte(0);
}
} }
} }
} }
public void write(DataOutput output, RegularMethodNode method) throws IOException { public void write(VarDataOutput output, RegularMethodNode method) throws IOException {
output.writeInt(ElementModifier.pack(method.getModifiers())); output.writeUnsigned(ElementModifier.pack(method.getModifiers()));
output.writeShort(method.getVariables().size()); output.writeUnsigned(method.getVariables().size());
for (VariableNode var : method.getVariables()) { for (VariableNode var : method.getVariables()) {
write(output, var); write(output, var);
} }
@ -122,33 +114,31 @@ public class AstIO {
} }
} }
private void write(DataOutput output, VariableNode variable) throws IOException { private void write(VarDataOutput output, VariableNode variable) throws IOException {
output.writeShort(variable.getIndex()); output.writeUnsigned(variable.getIndex());
output.writeByte(variable.getType().ordinal()); output.writeUnsigned(variable.getType().ordinal());
output.writeUTF(variable.getName() != null ? variable.getName() : ""); output.write(variable.getName());
} }
public ControlFlowEntry[] readControlFlow(DataInput input) throws IOException { public ControlFlowEntry[] readControlFlow(VarDataInput input) throws IOException {
short size = input.readShort(); 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) {
TextLocation from = readLocation(input); TextLocation from = readLocation(input);
int toSize = input.readShort(); int toSize = input.readUnsigned();
TextLocation[] to = new TextLocation[toSize]; TextLocation[] to = new TextLocation[toSize];
for (int j = 0; j < toSize; ++j) { for (int j = 0; j < toSize; ++j) {
if (input.readByte() != 0) {
to[j] = readLocation(input); to[j] = readLocation(input);
} }
}
result[i] = new ControlFlowEntry(from, to); result[i] = new ControlFlowEntry(from, to);
} }
return result; return result;
} }
public RegularMethodNode read(DataInput input, MethodReference method) throws IOException { public RegularMethodNode read(VarDataInput input, MethodReference method) throws IOException {
RegularMethodNode node = new RegularMethodNode(method); RegularMethodNode node = new RegularMethodNode(method);
node.getModifiers().addAll(unpackModifiers(input.readInt())); node.getModifiers().addAll(unpackModifiers(input.readUnsigned()));
int varCount = input.readShort(); int varCount = input.readUnsigned();
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
node.getVariables().add(readVariable(input)); node.getVariables().add(readVariable(input));
} }
@ -156,28 +146,22 @@ public class AstIO {
return node; return node;
} }
private VariableNode readVariable(DataInput input) throws IOException { private VariableNode readVariable(VarDataInput input) throws IOException {
int index = input.readShort(); int index = input.readUnsigned();
VariableType type = VariableType.values()[input.readByte()]; VariableType type = VariableType.values()[input.readUnsigned()];
VariableNode variable = new VariableNode(index, type); VariableNode variable = new VariableNode(index, type);
int nameCount = input.readByte(); variable.setName(input.read());
for (int i = 0; i < nameCount; ++i) {
variable.setName(input.readUTF());
if (variable.getName().isEmpty()) {
variable.setName(null);
}
}
return variable; return variable;
} }
public void writeAsync(DataOutput output, AsyncMethodNode method) throws IOException { public void writeAsync(VarDataOutput output, AsyncMethodNode method) throws IOException {
output.writeInt(ElementModifier.pack(method.getModifiers())); output.writeUnsigned(ElementModifier.pack(method.getModifiers()));
output.writeShort(method.getVariables().size()); output.writeUnsigned(method.getVariables().size());
for (VariableNode var : method.getVariables()) { for (VariableNode var : method.getVariables()) {
write(output, var); write(output, var);
} }
try { try {
output.writeShort(method.getBody().size()); output.writeUnsigned(method.getBody().size());
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(new NodeWriter(output));
} }
@ -186,14 +170,14 @@ public class AstIO {
} }
} }
public AsyncMethodNode readAsync(DataInput input, MethodReference method) throws IOException { public AsyncMethodNode readAsync(VarDataInput input, MethodReference method) throws IOException {
AsyncMethodNode node = new AsyncMethodNode(method); AsyncMethodNode node = new AsyncMethodNode(method);
node.getModifiers().addAll(unpackModifiers(input.readInt())); node.getModifiers().addAll(unpackModifiers(input.readUnsigned()));
int varCount = input.readShort(); int varCount = input.readUnsigned();
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
node.getVariables().add(readVariable(input)); node.getVariables().add(readVariable(input));
} }
int partCount = input.readShort(); int partCount = input.readUnsigned();
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));
@ -212,19 +196,19 @@ public class AstIO {
return modifiers; return modifiers;
} }
private void writeLocation(DataOutput 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.writeShort(-1); output.writeUnsigned(0);
} else { } else {
output.writeShort(fileTable.lookup(location.getFileName())); output.writeUnsigned(fileTable.lookup(location.getFileName()) + 1);
output.writeShort(location.getLine()); output.writeUnsigned(location.getLine());
} }
} }
private class NodeWriter implements ExprVisitor, StatementVisitor { private class NodeWriter implements ExprVisitor, StatementVisitor {
private final DataOutput output; private final VarDataOutput output;
NodeWriter(DataOutput output) { NodeWriter(VarDataOutput output) {
super(); super();
this.output = output; this.output = output;
} }
@ -239,31 +223,22 @@ public class AstIO {
} }
private void writeSequence(List<Statement> sequence) throws IOException { private void writeSequence(List<Statement> sequence) throws IOException {
output.writeShort(sequence.size()); output.writeUnsigned(sequence.size());
for (Statement part : sequence) { for (Statement part : sequence) {
part.acceptVisitor(this); part.acceptVisitor(this);
} }
} }
private void writeNullableString(String str) throws IOException {
if (str == null) {
output.writeBoolean(false);
} else {
output.writeBoolean(true);
output.writeUTF(str);
}
}
@Override @Override
public void visit(AssignmentStatement statement) { public void visit(AssignmentStatement statement) {
try { try {
output.writeByte(statement.getLeftValue() != null ? 0 : 1); output.writeUnsigned(statement.getLeftValue() != null ? 0 : 1);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
if (statement.getLeftValue() != null) { if (statement.getLeftValue() != null) {
writeExpr(statement.getLeftValue()); writeExpr(statement.getLeftValue());
} }
writeExpr(statement.getRightValue()); writeExpr(statement.getRightValue());
output.writeBoolean(statement.isAsync()); output.writeUnsigned(statement.isAsync() ? 1 : 0);
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -272,7 +247,7 @@ public class AstIO {
@Override @Override
public void visit(SequentialStatement statement) { public void visit(SequentialStatement statement) {
try { try {
output.writeByte(2); output.writeUnsigned(2);
writeSequence(statement.getSequence()); writeSequence(statement.getSequence());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -282,7 +257,7 @@ public class AstIO {
@Override @Override
public void visit(ConditionalStatement statement) { public void visit(ConditionalStatement statement) {
try { try {
output.writeByte(3); output.writeUnsigned(3);
writeExpr(statement.getCondition()); writeExpr(statement.getCondition());
writeSequence(statement.getConsequent()); writeSequence(statement.getConsequent());
writeSequence(statement.getAlternative()); writeSequence(statement.getAlternative());
@ -294,15 +269,15 @@ public class AstIO {
@Override @Override
public void visit(SwitchStatement statement) { public void visit(SwitchStatement statement) {
try { try {
output.writeByte(4); output.writeUnsigned(4);
writeNullableString(statement.getId()); output.write(statement.getId());
writeExpr(statement.getValue()); writeExpr(statement.getValue());
output.writeShort(statement.getClauses().size()); output.writeUnsigned(statement.getClauses().size());
for (SwitchClause clause : statement.getClauses()) { for (SwitchClause clause : statement.getClauses()) {
int[] conditions = clause.getConditions(); int[] conditions = clause.getConditions();
output.writeShort(conditions.length); output.writeUnsigned(conditions.length);
for (int condition : conditions) { for (int condition : conditions) {
output.writeInt(condition); output.writeSigned(condition);
} }
writeSequence(clause.getBody()); writeSequence(clause.getBody());
} }
@ -315,8 +290,8 @@ public class AstIO {
@Override @Override
public void visit(WhileStatement statement) { public void visit(WhileStatement statement) {
try { try {
output.writeByte(statement.getCondition() != null ? 5 : 6); output.writeUnsigned(statement.getCondition() != null ? 5 : 6);
writeNullableString(statement.getId()); output.write(statement.getId());
if (statement.getCondition() != null) { if (statement.getCondition() != null) {
writeExpr(statement.getCondition()); writeExpr(statement.getCondition());
} }
@ -329,8 +304,8 @@ public class AstIO {
@Override @Override
public void visit(BlockStatement statement) { public void visit(BlockStatement statement) {
try { try {
output.writeByte(7); output.writeUnsigned(7);
writeNullableString(statement.getId()); output.write(statement.getId());
writeSequence(statement.getBody()); writeSequence(statement.getBody());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -340,10 +315,10 @@ public class AstIO {
@Override @Override
public void visit(BreakStatement statement) { public void visit(BreakStatement statement) {
try { try {
output.writeByte(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9); output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 8 : 9);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
if (statement.getTarget() != null && statement.getTarget().getId() != null) { if (statement.getTarget() != null && statement.getTarget().getId() != null) {
output.writeUTF(statement.getTarget().getId()); output.write(statement.getTarget().getId());
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -353,10 +328,10 @@ public class AstIO {
@Override @Override
public void visit(ContinueStatement statement) { public void visit(ContinueStatement statement) {
try { try {
output.writeByte(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11); output.writeUnsigned(statement.getTarget() != null && statement.getTarget().getId() != null ? 10 : 11);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
if (statement.getTarget() != null && statement.getTarget().getId() != null) { if (statement.getTarget() != null && statement.getTarget().getId() != null) {
output.writeUTF(statement.getTarget().getId()); output.write(statement.getTarget().getId());
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -366,7 +341,7 @@ public class AstIO {
@Override @Override
public void visit(ReturnStatement statement) { public void visit(ReturnStatement statement) {
try { try {
output.writeByte(statement.getResult() != null ? 12 : 13); output.writeUnsigned(statement.getResult() != null ? 12 : 13);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
if (statement.getResult() != null) { if (statement.getResult() != null) {
writeExpr(statement.getResult()); writeExpr(statement.getResult());
@ -379,7 +354,7 @@ public class AstIO {
@Override @Override
public void visit(ThrowStatement statement) { public void visit(ThrowStatement statement) {
try { try {
output.writeByte(14); output.writeUnsigned(14);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
writeExpr(statement.getException()); writeExpr(statement.getException());
} catch (IOException e) { } catch (IOException e) {
@ -390,9 +365,9 @@ public class AstIO {
@Override @Override
public void visit(InitClassStatement statement) { public void visit(InitClassStatement statement) {
try { try {
output.writeByte(15); output.writeUnsigned(15);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeInt(symbolTable.lookup(statement.getClassName())); output.writeUnsigned(symbolTable.lookup(statement.getClassName()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -401,12 +376,12 @@ public class AstIO {
@Override @Override
public void visit(TryCatchStatement statement) { public void visit(TryCatchStatement statement) {
try { try {
output.writeByte(16); output.writeUnsigned(16);
writeSequence(statement.getProtectedBody()); writeSequence(statement.getProtectedBody());
output.writeInt(statement.getExceptionType() != null output.writeUnsigned(statement.getExceptionType() != null
? symbolTable.lookup(statement.getExceptionType()) : -1); ? symbolTable.lookup(statement.getExceptionType()) + 1 : 0);
output.writeShort(statement.getExceptionVariable() != null output.writeUnsigned(statement.getExceptionVariable() != null
? statement.getExceptionVariable() : -1); ? statement.getExceptionVariable() + 1 : 0);
writeSequence(statement.getHandler()); writeSequence(statement.getHandler());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -416,8 +391,8 @@ public class AstIO {
@Override @Override
public void visit(GotoPartStatement statement) { public void visit(GotoPartStatement statement) {
try { try {
output.writeByte(17); output.writeUnsigned(17);
output.writeShort(statement.getPart()); output.writeUnsigned(statement.getPart());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -426,7 +401,7 @@ public class AstIO {
@Override @Override
public void visit(MonitorEnterStatement statement) { public void visit(MonitorEnterStatement statement) {
try { try {
output.writeByte(18); output.writeUnsigned(18);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
writeExpr(statement.getObjectRef()); writeExpr(statement.getObjectRef());
} catch (IOException e) { } catch (IOException e) {
@ -437,7 +412,7 @@ public class AstIO {
@Override @Override
public void visit(MonitorExitStatement statement) { public void visit(MonitorExitStatement statement) {
try { try {
output.writeByte(19); output.writeUnsigned(19);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
writeExpr(statement.getObjectRef()); writeExpr(statement.getObjectRef());
} catch (IOException e) { } catch (IOException e) {
@ -448,9 +423,9 @@ public class AstIO {
@Override @Override
public void visit(BinaryExpr expr) { public void visit(BinaryExpr expr) {
try { try {
output.writeByte(0); output.writeUnsigned(0);
output.writeByte(expr.getOperation().ordinal()); output.writeUnsigned(expr.getOperation().ordinal());
output.writeByte(expr.getType() != null ? expr.getType().ordinal() + 1 : 0); output.writeUnsigned(expr.getType() != null ? expr.getType().ordinal() + 1 : 0);
writeExpr(expr.getFirstOperand()); writeExpr(expr.getFirstOperand());
writeExpr(expr.getSecondOperand()); writeExpr(expr.getSecondOperand());
} catch (IOException e) { } catch (IOException e) {
@ -461,9 +436,9 @@ public class AstIO {
@Override @Override
public void visit(UnaryExpr expr) { public void visit(UnaryExpr expr) {
try { try {
output.writeByte(1); output.writeUnsigned(1);
output.writeByte(expr.getOperation().ordinal()); output.writeUnsigned(expr.getOperation().ordinal());
output.writeByte(expr.getType() != null ? expr.getType().ordinal() + 1 : 0); output.writeUnsigned(expr.getType() != null ? expr.getType().ordinal() + 1 : 0);
writeExpr(expr.getOperand()); writeExpr(expr.getOperand());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -473,7 +448,7 @@ public class AstIO {
@Override @Override
public void visit(ConditionalExpr expr) { public void visit(ConditionalExpr expr) {
try { try {
output.writeByte(2); output.writeUnsigned(2);
writeExpr(expr.getCondition()); writeExpr(expr.getCondition());
writeExpr(expr.getConsequent()); writeExpr(expr.getConsequent());
writeExpr(expr.getAlternative()); writeExpr(expr.getAlternative());
@ -487,25 +462,25 @@ public class AstIO {
try { try {
Object value = expr.getValue(); Object value = expr.getValue();
if (value == null) { if (value == null) {
output.writeByte(3); output.writeUnsigned(3);
} else if (value instanceof Integer) { } else if (value instanceof Integer) {
output.writeByte(4); output.writeUnsigned(4);
output.writeInt((Integer) value); output.writeSigned((Integer) value);
} else if (value instanceof Long) { } else if (value instanceof Long) {
output.writeByte(5); output.writeUnsigned(5);
output.writeLong((Long) value); output.writeSigned((Long) value);
} else if (value instanceof Float) { } else if (value instanceof Float) {
output.writeByte(6); output.writeUnsigned(6);
output.writeFloat((Float) value); output.writeFloat((Float) value);
} else if (value instanceof Double) { } else if (value instanceof Double) {
output.writeByte(7); output.writeUnsigned(7);
output.writeDouble((Double) value); output.writeDouble((Double) value);
} else if (value instanceof String) { } else if (value instanceof String) {
output.writeByte(8); output.writeUnsigned(8);
output.writeUTF((String) value); output.write((String) value);
} else if (value instanceof ValueType) { } else if (value instanceof ValueType) {
output.writeByte(9); output.writeUnsigned(9);
output.writeInt(symbolTable.lookup(value.toString())); output.writeUnsigned(symbolTable.lookup(value.toString()));
} }
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -515,8 +490,8 @@ public class AstIO {
@Override @Override
public void visit(VariableExpr expr) { public void visit(VariableExpr expr) {
try { try {
output.writeByte(10); output.writeUnsigned(10);
output.writeShort(expr.getIndex()); output.writeUnsigned(expr.getIndex());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -525,10 +500,10 @@ public class AstIO {
@Override @Override
public void visit(SubscriptExpr expr) { public void visit(SubscriptExpr expr) {
try { try {
output.writeByte(11); output.writeUnsigned(11);
writeExpr(expr.getArray()); writeExpr(expr.getArray());
writeExpr(expr.getIndex()); writeExpr(expr.getIndex());
output.writeByte(expr.getType().ordinal()); output.writeUnsigned(expr.getType().ordinal());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -537,8 +512,8 @@ public class AstIO {
@Override @Override
public void visit(UnwrapArrayExpr expr) { public void visit(UnwrapArrayExpr expr) {
try { try {
output.writeByte(12); output.writeUnsigned(12);
output.writeByte(expr.getElementType().ordinal()); output.writeUnsigned(expr.getElementType().ordinal());
writeExpr(expr.getArray()); writeExpr(expr.getArray());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -550,21 +525,21 @@ public class AstIO {
try { try {
switch (expr.getType()) { switch (expr.getType()) {
case CONSTRUCTOR: case CONSTRUCTOR:
output.writeByte(13); output.writeUnsigned(13);
break; break;
case STATIC: case STATIC:
output.writeByte(14); output.writeUnsigned(14);
break; break;
case SPECIAL: case SPECIAL:
output.writeByte(15); output.writeUnsigned(15);
break; break;
case DYNAMIC: case DYNAMIC:
output.writeByte(16); output.writeUnsigned(16);
break; break;
} }
output.writeInt(symbolTable.lookup(expr.getMethod().getClassName())); output.writeUnsigned(symbolTable.lookup(expr.getMethod().getClassName()));
output.writeInt(symbolTable.lookup(expr.getMethod().getDescriptor().toString())); output.writeUnsigned(symbolTable.lookup(expr.getMethod().getDescriptor().toString()));
output.writeShort(expr.getArguments().size()); output.writeUnsigned(expr.getArguments().size());
for (int i = 0; i < expr.getArguments().size(); ++i) { for (int i = 0; i < expr.getArguments().size(); ++i) {
writeExpr(expr.getArguments().get(i)); writeExpr(expr.getArguments().get(i));
} }
@ -576,12 +551,12 @@ public class AstIO {
@Override @Override
public void visit(QualificationExpr expr) { public void visit(QualificationExpr expr) {
try { try {
output.writeByte(expr.getQualified() != null ? 17 : 18); output.writeUnsigned(expr.getQualified() == null ? 17 : 18);
if (expr.getQualified() != null) { if (expr.getQualified() != null) {
writeExpr(expr.getQualified()); writeExpr(expr.getQualified());
} }
output.writeInt(symbolTable.lookup(expr.getField().getClassName())); output.writeUnsigned(symbolTable.lookup(expr.getField().getClassName()));
output.writeInt(symbolTable.lookup(expr.getField().getFieldName())); output.writeUnsigned(symbolTable.lookup(expr.getField().getFieldName()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -590,8 +565,8 @@ public class AstIO {
@Override @Override
public void visit(NewExpr expr) { public void visit(NewExpr expr) {
try { try {
output.writeByte(19); output.writeUnsigned(19);
output.writeInt(symbolTable.lookup(expr.getConstructedClass())); output.writeUnsigned(symbolTable.lookup(expr.getConstructedClass()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -600,9 +575,9 @@ public class AstIO {
@Override @Override
public void visit(NewArrayExpr expr) { public void visit(NewArrayExpr expr) {
try { try {
output.writeByte(20); output.writeUnsigned(20);
writeExpr(expr.getLength()); writeExpr(expr.getLength());
output.writeInt(symbolTable.lookup(expr.getType().toString())); output.writeUnsigned(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -611,12 +586,12 @@ public class AstIO {
@Override @Override
public void visit(NewMultiArrayExpr expr) { public void visit(NewMultiArrayExpr expr) {
try { try {
output.writeByte(21); output.writeUnsigned(21);
output.writeByte(expr.getDimensions().size()); output.writeUnsigned(expr.getDimensions().size());
for (Expr dimension : expr.getDimensions()) { for (Expr dimension : expr.getDimensions()) {
writeExpr(dimension); writeExpr(dimension);
} }
output.writeInt(symbolTable.lookup(expr.getType().toString())); output.writeUnsigned(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -625,9 +600,9 @@ public class AstIO {
@Override @Override
public void visit(InstanceOfExpr expr) { public void visit(InstanceOfExpr expr) {
try { try {
output.writeByte(22); output.writeUnsigned(22);
writeExpr(expr.getExpr()); writeExpr(expr.getExpr());
output.writeInt(symbolTable.lookup(expr.getType().toString())); output.writeUnsigned(symbolTable.lookup(expr.getType().toString()));
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
@ -636,8 +611,8 @@ public class AstIO {
@Override @Override
public void visit(CastExpr expr) { public void visit(CastExpr expr) {
try { try {
output.writeByte(23); output.writeUnsigned(23);
output.writeInt(symbolTable.lookup(expr.getTarget().toString())); output.writeUnsigned(symbolTable.lookup(expr.getTarget().toString()));
writeExpr(expr.getValue()); writeExpr(expr.getValue());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -647,9 +622,9 @@ public class AstIO {
@Override @Override
public void visit(PrimitiveCastExpr expr) { public void visit(PrimitiveCastExpr expr) {
try { try {
output.writeByte(24); output.writeUnsigned(24);
output.writeByte(expr.getSource().ordinal()); output.writeUnsigned(expr.getSource().ordinal());
output.writeByte(expr.getTarget().ordinal()); output.writeUnsigned(expr.getTarget().ordinal());
writeExpr(expr.getValue()); writeExpr(expr.getValue());
} catch (IOException e) { } catch (IOException e) {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
@ -657,31 +632,31 @@ public class AstIO {
} }
} }
private TextLocation readLocation(DataInput input) throws IOException { private TextLocation readLocation(VarDataInput input) throws IOException {
int fileIndex = input.readShort(); int fileIndex = input.readUnsigned();
if (fileIndex == -1) { if (fileIndex == 0) {
return null; return null;
} else { } else {
return new TextLocation(fileTable.at(fileIndex), input.readShort()); return new TextLocation(fileTable.at(fileIndex - 1), input.readUnsigned());
} }
} }
private Statement readStatement(DataInput input) throws IOException { private Statement readStatement(VarDataInput input) throws IOException {
byte type = input.readByte(); int type = input.readUnsigned();
switch (type) { switch (type) {
case 0: { case 0: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
stmt.setLeftValue(readExpr(input)); stmt.setLeftValue(readExpr(input));
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readBoolean()); stmt.setAsync(input.readUnsigned() != 0);
return stmt; return stmt;
} }
case 1: { case 1: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readBoolean()); stmt.setAsync(input.readUnsigned() != 0);
return stmt; return stmt;
} }
case 2: { case 2: {
@ -698,15 +673,15 @@ public class AstIO {
} }
case 4: { case 4: {
SwitchStatement stmt = new SwitchStatement(); SwitchStatement stmt = new SwitchStatement();
stmt.setId(readNullableString(input)); stmt.setId(input.read());
stmt.setValue(readExpr(input)); stmt.setValue(readExpr(input));
int clauseCount = input.readShort(); int clauseCount = input.readUnsigned();
for (int i = 0; i < clauseCount; ++i) { for (int i = 0; i < clauseCount; ++i) {
SwitchClause clause = new SwitchClause(); SwitchClause clause = new SwitchClause();
int conditionCount = input.readShort(); int conditionCount = input.readUnsigned();
int[] conditions = new int[conditionCount]; int[] conditions = new int[conditionCount];
for (int j = 0; j < conditionCount; ++j) { for (int j = 0; j < conditionCount; ++j) {
conditions[j] = input.readInt(); conditions[j] = input.readSigned();
} }
clause.setConditions(conditions); clause.setConditions(conditions);
readSequence(input, clause.getBody()); readSequence(input, clause.getBody());
@ -717,7 +692,7 @@ public class AstIO {
} }
case 5: { case 5: {
WhileStatement stmt = new WhileStatement(); WhileStatement stmt = new WhileStatement();
stmt.setId(readNullableString(input)); stmt.setId(input.read());
stmt.setCondition(readExpr(input)); stmt.setCondition(readExpr(input));
if (stmt.getId() != null) { if (stmt.getId() != null) {
statementMap.put(stmt.getId(), stmt); statementMap.put(stmt.getId(), stmt);
@ -727,7 +702,7 @@ public class AstIO {
} }
case 6: { case 6: {
WhileStatement stmt = new WhileStatement(); WhileStatement stmt = new WhileStatement();
stmt.setId(readNullableString(input)); stmt.setId(input.read());
if (stmt.getId() != null) { if (stmt.getId() != null) {
statementMap.put(stmt.getId(), stmt); statementMap.put(stmt.getId(), stmt);
} }
@ -736,7 +711,7 @@ public class AstIO {
} }
case 7: { case 7: {
BlockStatement stmt = new BlockStatement(); BlockStatement stmt = new BlockStatement();
stmt.setId(readNullableString(input)); stmt.setId(input.read());
if (stmt.getId() != null) { if (stmt.getId() != null) {
statementMap.put(stmt.getId(), stmt); statementMap.put(stmt.getId(), stmt);
} }
@ -746,7 +721,7 @@ public class AstIO {
case 8: { case 8: {
BreakStatement stmt = new BreakStatement(); BreakStatement stmt = new BreakStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
stmt.setTarget(statementMap.get(input.readUTF())); stmt.setTarget(statementMap.get(input.read()));
return stmt; return stmt;
} }
case 9: { case 9: {
@ -757,7 +732,7 @@ public class AstIO {
case 10: { case 10: {
ContinueStatement stmt = new ContinueStatement(); ContinueStatement stmt = new ContinueStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
stmt.setTarget(statementMap.get(input.readUTF())); stmt.setTarget(statementMap.get(input.read()));
return stmt; return stmt;
} }
case 11: { case 11: {
@ -785,26 +760,26 @@ public class AstIO {
case 15: { case 15: {
InitClassStatement stmt = new InitClassStatement(); InitClassStatement stmt = new InitClassStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
stmt.setClassName(symbolTable.at(input.readInt())); stmt.setClassName(symbolTable.at(input.readUnsigned()));
return stmt; return stmt;
} }
case 16: { case 16: {
TryCatchStatement stmt = new TryCatchStatement(); TryCatchStatement stmt = new TryCatchStatement();
readSequence(input, stmt.getProtectedBody()); readSequence(input, stmt.getProtectedBody());
int exceptionTypeIndex = input.readInt(); int exceptionTypeIndex = input.readUnsigned();
if (exceptionTypeIndex >= 0) { if (exceptionTypeIndex > 0) {
stmt.setExceptionType(symbolTable.at(exceptionTypeIndex)); stmt.setExceptionType(symbolTable.at(exceptionTypeIndex - 1));
} }
int exceptionVarIndex = input.readShort(); int exceptionVarIndex = input.readUnsigned();
if (exceptionVarIndex >= 0) { if (exceptionVarIndex > 0) {
stmt.setExceptionVariable(exceptionVarIndex); stmt.setExceptionVariable(exceptionVarIndex - 1);
} }
readSequence(input, stmt.getHandler()); readSequence(input, stmt.getHandler());
return stmt; return stmt;
} }
case 17: { case 17: {
GotoPartStatement stmt = new GotoPartStatement(); GotoPartStatement stmt = new GotoPartStatement();
stmt.setPart(input.readShort()); stmt.setPart(input.readUnsigned());
return stmt; return stmt;
} }
case 18: { case 18: {
@ -824,41 +799,37 @@ public class AstIO {
} }
} }
private void readSequence(DataInput input, List<Statement> statements) throws IOException { private void readSequence(VarDataInput input, List<Statement> statements) throws IOException {
int count = input.readShort(); int count = input.readUnsigned();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
statements.add(readStatement(input)); statements.add(readStatement(input));
} }
} }
private String readNullableString(DataInput input) throws IOException { private Expr readExpr(VarDataInput input) throws IOException {
return input.readBoolean() ? input.readUTF() : null;
}
private Expr readExpr(DataInput input) throws IOException {
TextLocation location = readLocation(input); TextLocation location = readLocation(input);
Expr expr = readExprWithoutLocation(input); Expr expr = readExprWithoutLocation(input);
expr.setLocation(location); expr.setLocation(location);
return expr; return expr;
} }
private Expr readExprWithoutLocation(DataInput input) throws IOException { private Expr readExprWithoutLocation(VarDataInput input) throws IOException {
byte type = input.readByte(); int type = input.readUnsigned();
switch (type) { switch (type) {
case 0: { case 0: {
BinaryExpr expr = new BinaryExpr(); BinaryExpr expr = new BinaryExpr();
expr.setOperation(binaryOperations[input.readByte()]); expr.setOperation(binaryOperations[input.readUnsigned()]);
byte valueType = input.readByte(); int valueType = input.readUnsigned();
expr.setType(valueType > 0 ? OperationType.values()[valueType] : null); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null);
expr.setFirstOperand(readExpr(input)); expr.setFirstOperand(readExpr(input));
expr.setSecondOperand(readExpr(input)); expr.setSecondOperand(readExpr(input));
return expr; return expr;
} }
case 1: { case 1: {
UnaryExpr expr = new UnaryExpr(); UnaryExpr expr = new UnaryExpr();
expr.setOperation(unaryOperations[input.readByte()]); expr.setOperation(unaryOperations[input.readUnsigned()]);
byte valueType = input.readByte(); int valueType = input.readUnsigned();
expr.setType(valueType > 0 ? OperationType.values()[valueType] : null); expr.setType(valueType > 0 ? OperationType.values()[valueType - 1] : null);
expr.setOperand(readExpr(input)); expr.setOperand(readExpr(input));
return expr; return expr;
} }
@ -874,12 +845,12 @@ public class AstIO {
} }
case 4: { case 4: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setValue(input.readInt()); expr.setValue(input.readSigned());
return expr; return expr;
} }
case 5: { case 5: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setValue(input.readLong()); expr.setValue(input.readSignedLong());
return expr; return expr;
} }
case 6: { case 6: {
@ -894,28 +865,28 @@ public class AstIO {
} }
case 8: { case 8: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setValue(input.readUTF()); expr.setValue(input.read());
return expr; return expr;
} }
case 9: { case 9: {
ConstantExpr expr = new ConstantExpr(); ConstantExpr expr = new ConstantExpr();
expr.setValue(ValueType.parse(symbolTable.at(input.readInt()))); 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.setIndex(input.readShort()); expr.setIndex(input.readUnsigned());
return expr; return expr;
} }
case 11: { case 11: {
SubscriptExpr expr = new SubscriptExpr(); SubscriptExpr expr = new SubscriptExpr();
expr.setArray(readExpr(input)); expr.setArray(readExpr(input));
expr.setIndex(readExpr(input)); expr.setIndex(readExpr(input));
expr.setType(ArrayType.values()[input.readByte()]); expr.setType(ArrayType.values()[input.readUnsigned()]);
return expr; return expr;
} }
case 12: { case 12: {
UnwrapArrayExpr expr = new UnwrapArrayExpr(ArrayType.values()[input.readByte()]); UnwrapArrayExpr expr = new UnwrapArrayExpr(ArrayType.values()[input.readUnsigned()]);
expr.setArray(readExpr(input)); expr.setArray(readExpr(input));
return expr; return expr;
} }
@ -929,55 +900,55 @@ 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();
String className = symbolTable.at(input.readInt()); String className = symbolTable.at(input.readUnsigned());
String fieldName = symbolTable.at(input.readInt()); String fieldName = symbolTable.at(input.readUnsigned());
expr.setField(new FieldReference(className, fieldName)); expr.setField(new FieldReference(className, fieldName));
return expr; return expr;
} }
case 18: { case 18: {
QualificationExpr expr = new QualificationExpr(); QualificationExpr expr = new QualificationExpr();
expr.setQualified(readExpr(input)); expr.setQualified(readExpr(input));
String className = symbolTable.at(input.readInt()); String className = symbolTable.at(input.readUnsigned());
String fieldName = symbolTable.at(input.readInt()); String fieldName = symbolTable.at(input.readUnsigned());
expr.setField(new FieldReference(className, fieldName)); expr.setField(new FieldReference(className, fieldName));
return expr; return expr;
} }
case 19: { case 19: {
NewExpr expr = new NewExpr(); NewExpr expr = new NewExpr();
expr.setConstructedClass(symbolTable.at(input.readInt())); expr.setConstructedClass(symbolTable.at(input.readUnsigned()));
return expr; return expr;
} }
case 20: { case 20: {
NewArrayExpr expr = new NewArrayExpr(); NewArrayExpr expr = new NewArrayExpr();
expr.setLength(readExpr(input)); expr.setLength(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readInt()))); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
return expr; return expr;
} }
case 21: { case 21: {
NewMultiArrayExpr expr = new NewMultiArrayExpr(); NewMultiArrayExpr expr = new NewMultiArrayExpr();
int dimensionCount = input.readByte(); 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));
} }
expr.setType(ValueType.parse(symbolTable.at(input.readInt()))); expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
return expr; return expr;
} }
case 22: { case 22: {
InstanceOfExpr expr = new InstanceOfExpr(); InstanceOfExpr expr = new InstanceOfExpr();
expr.setExpr(readExpr(input)); expr.setExpr(readExpr(input));
expr.setType(ValueType.parse(symbolTable.at(input.readInt()))); 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.setTarget(ValueType.parse(symbolTable.at(input.readInt()))); 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.setSource(OperationType.values()[input.readByte()]); expr.setSource(OperationType.values()[input.readUnsigned()]);
expr.setTarget(OperationType.values()[input.readByte()]); expr.setTarget(OperationType.values()[input.readUnsigned()]);
expr.setValue(readExpr(input)); expr.setValue(readExpr(input));
return expr; return expr;
} }
@ -986,17 +957,14 @@ public class AstIO {
} }
} }
private InvocationExpr parseInvocationExpr(InvocationType invocationType, DataInput input) throws IOException { private InvocationExpr parseInvocationExpr(InvocationType invocationType, VarDataInput input) throws IOException {
InvocationExpr expr = new InvocationExpr(); InvocationExpr expr = new InvocationExpr();
expr.setType(invocationType); expr.setType(invocationType);
String className = symbolTable.at(input.readInt()); String className = symbolTable.at(input.readUnsigned());
MethodDescriptor method = methodDescriptorCache.computeIfAbsent(symbolTable.at(input.readInt()), String signature = symbolTable.at(input.readUnsigned());
MethodDescriptor::parse); MethodReference methodRef = referenceCache.getCached(className, MethodDescriptor.parse(signature));
MethodReference methodRef = methodReferenceCache
.computeIfAbsent(className, k -> new HashMap<>())
.computeIfAbsent(method, k -> new MethodReference(className, k));
expr.setMethod(methodRef); expr.setMethod(methodRef);
int argCount = input.readShort(); int argCount = input.readUnsigned();
for (int i = 0; i < argCount; ++i) { for (int i = 0; i < argCount; ++i) {
expr.getArguments().add(readExpr(input)); expr.getArguments().add(readExpr(input));
} }

View File

@ -17,9 +17,6 @@ package org.teavm.cache;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -57,7 +54,7 @@ public class DiskMethodNodeCache implements MethodNodeCache {
File file = getMethodFile(methodReference, false); File file = getMethodFile(methodReference, false);
if (file.exists()) { if (file.exists()) {
try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) { try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) {
DataInput input = new DataInputStream(stream); VarDataInput input = new VarDataInput(stream);
if (!checkIfDependenciesChanged(input, cacheStatus)) { if (!checkIfDependenciesChanged(input, cacheStatus)) {
RegularMethodNode node = astIO.read(input, methodReference); RegularMethodNode node = astIO.read(input, methodReference);
ControlFlowEntry[] cfg = astIO.readControlFlow(input); ControlFlowEntry[] cfg = astIO.readControlFlow(input);
@ -89,7 +86,7 @@ public class DiskMethodNodeCache implements MethodNodeCache {
File file = getMethodFile(methodReference, true); File file = getMethodFile(methodReference, true);
if (file.exists()) { if (file.exists()) {
try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) { try (InputStream stream = new BufferedInputStream(new FileInputStream(file))) {
DataInput input = new DataInputStream(stream); VarDataInput input = new VarDataInput(stream);
if (!checkIfDependenciesChanged(input, cacheStatus)) { if (!checkIfDependenciesChanged(input, cacheStatus)) {
item.node = astIO.readAsync(input, methodReference); item.node = astIO.readAsync(input, methodReference);
} }
@ -101,10 +98,10 @@ public class DiskMethodNodeCache implements MethodNodeCache {
return item.node; return item.node;
} }
private boolean checkIfDependenciesChanged(DataInput input, CacheStatus cacheStatus) throws IOException { private boolean checkIfDependenciesChanged(VarDataInput input, CacheStatus cacheStatus) throws IOException {
int depCount = input.readShort(); int depCount = input.readUnsigned();
for (int i = 0; i < depCount; ++i) { for (int i = 0; i < depCount; ++i) {
String depClass = input.readUTF(); String depClass = input.read();
if (cacheStatus.isStaleClass(depClass)) { if (cacheStatus.isStaleClass(depClass)) {
return true; return true;
} }
@ -125,10 +122,10 @@ public class DiskMethodNodeCache implements MethodNodeCache {
for (MethodReference method : newMethods) { for (MethodReference method : newMethods) {
File file = getMethodFile(method, true); File file = getMethodFile(method, true);
Item item = cache.get(method); Item item = cache.get(method);
try (DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { try (VarDataOutput output = new VarDataOutput(new BufferedOutputStream(new FileOutputStream(file)))) {
output.writeShort(item.dependencies.length); output.writeUnsigned(item.dependencies.length);
for (String dependency : item.dependencies) { for (String dependency : item.dependencies) {
output.writeUTF(dependency); output.write(dependency);
} }
astIO.write(output, item.entry.method); astIO.write(output, item.entry.method);
astIO.write(output, item.entry.cfg); astIO.write(output, item.entry.cfg);
@ -137,10 +134,10 @@ public class DiskMethodNodeCache implements MethodNodeCache {
for (MethodReference method : newAsyncMethods) { for (MethodReference method : newAsyncMethods) {
File file = getMethodFile(method, true); File file = getMethodFile(method, true);
AsyncItem item = asyncCache.get(method); AsyncItem item = asyncCache.get(method);
try (DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { try (VarDataOutput output = new VarDataOutput(new BufferedOutputStream(new FileOutputStream(file)))) {
output.writeShort(item.dependencies.length); output.writeUnsigned(item.dependencies.length);
for (String dependency : item.dependencies) { for (String dependency : item.dependencies) {
output.writeUTF(dependency); output.write(dependency);
} }
astIO.writeAsync(output, item.node); astIO.writeAsync(output, item.node);
} }

View File

@ -15,11 +15,16 @@
*/ */
package org.teavm.cache; package org.teavm.cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.teavm.ast.AsyncMethodNode; import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.ControlFlowEntry;
import org.teavm.ast.RegularMethodNode;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class InMemoryMethodNodeCache implements MethodNodeCache { public class InMemoryMethodNodeCache implements MethodNodeCache {
@ -27,6 +32,11 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
private Map<MethodReference, RegularItem> newItems = new HashMap<>(); private Map<MethodReference, RegularItem> newItems = new HashMap<>();
private Map<MethodReference, AsyncItem> asyncCache = new HashMap<>(); private Map<MethodReference, AsyncItem> asyncCache = new HashMap<>();
private Map<MethodReference, AsyncItem> newAsyncItems = new HashMap<>(); private Map<MethodReference, AsyncItem> newAsyncItems = new HashMap<>();
private AstIO io;
public InMemoryMethodNodeCache(InMemorySymbolTable symbolTable, InMemorySymbolTable fileSymbolTable) {
io = new AstIO(symbolTable, fileSymbolTable);
}
@Override @Override
public AstCacheEntry get(MethodReference methodReference, CacheStatus cacheStatus) { public AstCacheEntry get(MethodReference methodReference, CacheStatus cacheStatus) {
@ -39,7 +49,14 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
return null; return null;
} }
return item.entry; VarDataInput input = new VarDataInput(new ByteArrayInputStream(item.entry));
try {
ControlFlowEntry[] cfg = io.readControlFlow(input);
RegularMethodNode ast = io.read(input, methodReference);
return new AstCacheEntry(ast, cfg);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
@Override @Override
@ -58,7 +75,12 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
return null; return null;
} }
return item.node; VarDataInput input = new VarDataInput(new ByteArrayInputStream(item.node));
try {
return io.readAsync(input, methodReference);
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
@Override @Override
@ -85,22 +107,37 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
newAsyncItems.clear(); newAsyncItems.clear();
} }
static final class RegularItem { final class RegularItem {
final AstCacheEntry entry; final byte[] entry;
final String[] dependencies; final String[] dependencies;
RegularItem(AstCacheEntry entry, String[] dependencies) { RegularItem(AstCacheEntry entry, String[] dependencies) {
this.entry = entry; try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
VarDataOutput data = new VarDataOutput(output);
io.write(data, entry.cfg);
io.write(data, entry.method);
this.entry = output.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.dependencies = dependencies; this.dependencies = dependencies;
} }
} }
static final class AsyncItem { final class AsyncItem {
final AsyncMethodNode node; final byte[] node;
final String[] dependencies; final String[] dependencies;
AsyncItem(AsyncMethodNode node, String[] dependencies) { AsyncItem(AsyncMethodNode node, String[] dependencies) {
this.node = node; try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
VarDataOutput data = new VarDataOutput(output);
io.writeAsync(data, node);
this.node = output.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.dependencies = dependencies; this.dependencies = dependencies;
} }
} }

View File

@ -29,9 +29,11 @@ import org.teavm.model.ProgramCache;
public class InMemoryProgramCache implements ProgramCache { public class InMemoryProgramCache implements ProgramCache {
private Map<MethodReference, Item> cache = new HashMap<>(); private Map<MethodReference, Item> cache = new HashMap<>();
private Map<MethodReference, Item> newItems = new HashMap<>(); private Map<MethodReference, Item> newItems = new HashMap<>();
private InMemorySymbolTable symbolTable = new InMemorySymbolTable(); private ProgramIO io;
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
private ProgramIO io = new ProgramIO(new InMemorySymbolTable(), new InMemorySymbolTable()); public InMemoryProgramCache(InMemorySymbolTable symbolTable, InMemorySymbolTable fileSymbolTable) {
io = new ProgramIO(symbolTable, fileSymbolTable);
}
@Override @Override
public Program get(MethodReference method, CacheStatus cacheStatus) { public Program get(MethodReference method, CacheStatus cacheStatus) {
@ -78,8 +80,6 @@ public class InMemoryProgramCache implements ProgramCache {
public void invalidate() { public void invalidate() {
cache.clear(); cache.clear();
newItems.clear(); newItems.clear();
symbolTable.invalidate();
fileSymbolTable.invalidate();
} }
static final class Item { static final class Item {

View File

@ -20,7 +20,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
class InMemorySymbolTable implements SymbolTable { public class InMemorySymbolTable implements SymbolTable {
private List<String> symbols = new ArrayList<>(); private List<String> symbols = new ArrayList<>();
private Map<String, Integer> indexes = new HashMap<>(); private Map<String, Integer> indexes = new HashMap<>();

View File

@ -106,7 +106,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() != null ? var.getDebugName() : ""); data.write(var.getDebugName());
} }
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);
@ -159,9 +159,6 @@ public class ProgramIO {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setRegister(data.readUnsigned()); var.setRegister(data.readUnsigned());
var.setDebugName(referenceCache.getCached(data.read())); var.setDebugName(referenceCache.getCached(data.read()));
if (var.getDebugName().isEmpty()) {
var.setDebugName(null);
}
} }
for (int i = 0; i < basicBlockCount; ++i) { for (int i = 0; i < basicBlockCount; ++i) {
program.createBasicBlock(); program.createBasicBlock();

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.cache; package org.teavm.cache;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -33,6 +34,9 @@ public class VarDataInput {
int b; int b;
do { do {
b = input.read(); b = input.read();
if (b < 0) {
throw new EOFException();
}
value |= (b & DATA) << pos; value |= (b & DATA) << pos;
pos += 7; pos += 7;
} while ((b & NEXT) != 0); } while ((b & NEXT) != 0);
@ -41,7 +45,7 @@ public class VarDataInput {
public int readSigned() throws IOException { public int readSigned() throws IOException {
int value = readUnsigned(); int value = readUnsigned();
return (value & 1) == 0 ? (value >> 1) : -(value >> 1); return (value & 1) == 0 ? (value >>> 1) : -(value >>> 1);
} }
public long readUnsignedLong() throws IOException { public long readUnsignedLong() throws IOException {
@ -50,6 +54,9 @@ public class VarDataInput {
int b; int b;
do { do {
b = input.read(); b = input.read();
if (b < 0) {
throw new EOFException();
}
value |= ((long) b & DATA) << pos; value |= ((long) b & DATA) << pos;
pos += 7; pos += 7;
} while ((b & NEXT) != 0); } while ((b & NEXT) != 0);
@ -91,6 +98,10 @@ public class VarDataInput {
public String read() throws IOException { public String read() throws IOException {
int sz = readUnsigned(); int sz = readUnsigned();
if (sz == 0) {
return null;
}
sz--;
char[] chars = new char[sz]; char[] chars = new char[sz];
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
chars[i] = (char) readUnsigned(); chars[i] = (char) readUnsigned();

View File

@ -15,10 +15,11 @@
*/ */
package org.teavm.cache; package org.teavm.cache;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
public class VarDataOutput { public class VarDataOutput implements Closeable {
private static final int DATA = 0x7F; private static final int DATA = 0x7F;
private static final int NEXT = 0x80; private static final int NEXT = 0x80;
private OutputStream output; private OutputStream output;
@ -76,9 +77,18 @@ public class VarDataOutput {
} }
public void write(String s) throws IOException { public void write(String s) throws IOException {
writeUnsigned(s.length()); if (s == null) {
writeUnsigned(0);
return;
}
writeUnsigned(s.length() + 1);
for (int i = 0; i < s.length(); ++i) { for (int i = 0; i < s.length(); ++i) {
writeUnsigned(s.charAt(i)); writeUnsigned(s.charAt(i));
} }
} }
@Override
public void close() throws IOException {
output.close();
}
} }

View File

@ -48,6 +48,7 @@ import org.teavm.cache.AstCacheEntry;
import org.teavm.cache.CacheStatus; import org.teavm.cache.CacheStatus;
import org.teavm.cache.InMemoryMethodNodeCache; import org.teavm.cache.InMemoryMethodNodeCache;
import org.teavm.cache.InMemoryProgramCache; import org.teavm.cache.InMemoryProgramCache;
import org.teavm.cache.InMemorySymbolTable;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.dependency.FastDependencyAnalyzer; import org.teavm.dependency.FastDependencyAnalyzer;
import org.teavm.diagnostics.DefaultProblemTextConsumer; import org.teavm.diagnostics.DefaultProblemTextConsumer;
@ -236,6 +237,10 @@ public class IncrementalTest {
final Set<MethodReference> updatedMethods = new HashSet<>(); final Set<MethodReference> updatedMethods = new HashSet<>();
boolean capturing; boolean capturing;
CapturingMethodNodeCache() {
super(new InMemorySymbolTable(), new InMemorySymbolTable());
}
@Override @Override
public void store(MethodReference methodReference, AstCacheEntry node, Supplier<String[]> dependencies) { public void store(MethodReference methodReference, AstCacheEntry node, Supplier<String[]> dependencies) {
super.store(methodReference, node, dependencies); super.store(methodReference, node, dependencies);
@ -257,6 +262,10 @@ public class IncrementalTest {
final Set<MethodReference> updatedMethods = new HashSet<>(); final Set<MethodReference> updatedMethods = new HashSet<>();
boolean capturing; boolean capturing;
CapturingProgramCache() {
super(new InMemorySymbolTable(), new InMemorySymbolTable());
}
@Override @Override
public void store(MethodReference method, Program program, Supplier<String[]> dependencies) { public void store(MethodReference method, Program program, Supplier<String[]> dependencies) {
super.store(method, program, dependencies); super.store(method, program, dependencies);

View File

@ -69,6 +69,7 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.teavm.backend.javascript.JavaScriptTarget; import org.teavm.backend.javascript.JavaScriptTarget;
import org.teavm.cache.InMemoryMethodNodeCache; import org.teavm.cache.InMemoryMethodNodeCache;
import org.teavm.cache.InMemoryProgramCache; import org.teavm.cache.InMemoryProgramCache;
import org.teavm.cache.InMemorySymbolTable;
import org.teavm.cache.MemoryCachedClassReaderSource; import org.teavm.cache.MemoryCachedClassReaderSource;
import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.information.DebugInformationBuilder; import org.teavm.debugging.information.DebugInformationBuilder;
@ -136,6 +137,8 @@ public class CodeServlet extends HttpServlet {
private List<DevServerListener> listeners = new ArrayList<>(); private List<DevServerListener> listeners = new ArrayList<>();
private HttpClient httpClient; private HttpClient httpClient;
private WebSocketClient wsClient = new WebSocketClient(); private WebSocketClient wsClient = new WebSocketClient();
private InMemorySymbolTable symbolTable = new InMemorySymbolTable();
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
public CodeServlet(String mainClass, String[] classPath) { public CodeServlet(String mainClass, String[] classPath) {
this.mainClass = mainClass; this.mainClass = mainClass;
@ -223,6 +226,8 @@ public class CodeServlet extends HttpServlet {
astCache.invalidate(); astCache.invalidate();
programCache.invalidate(); programCache.invalidate();
classSource.invalidate(); classSource.invalidate();
symbolTable.invalidate();
fileSymbolTable.invalidate();
} }
} }
@ -702,8 +707,8 @@ public class CodeServlet extends HttpServlet {
watcher = new FileSystemWatcher(classPath); watcher = new FileSystemWatcher(classPath);
classSource = new MemoryCachedClassReaderSource(); classSource = new MemoryCachedClassReaderSource();
astCache = new InMemoryMethodNodeCache(); astCache = new InMemoryMethodNodeCache(symbolTable, fileSymbolTable);
programCache = new InMemoryProgramCache(); programCache = new InMemoryProgramCache(symbolTable, fileSymbolTable);
} }
private void shutdownBuilder() { private void shutdownBuilder() {