mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-18 04:14:50 -08:00
Reduce memory used by initial class reader
This commit is contained in:
parent
fcfa998e1c
commit
578912056b
351
core/src/main/java/org/teavm/cache/ClassIO.java
vendored
Normal file
351
core/src/main/java/org/teavm/cache/ClassIO.java
vendored
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.cache;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.model.AccessLevel;
|
||||||
|
import org.teavm.model.AnnotationContainer;
|
||||||
|
import org.teavm.model.AnnotationHolder;
|
||||||
|
import org.teavm.model.AnnotationReader;
|
||||||
|
import org.teavm.model.AnnotationValue;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.FieldHolder;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.ReferenceCache;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public class ClassIO {
|
||||||
|
private static AccessLevel[] accessLevels = AccessLevel.values();
|
||||||
|
private static ElementModifier[] elementModifiers = ElementModifier.values();
|
||||||
|
private SymbolTable symbolTable;
|
||||||
|
private ProgramIO programIO;
|
||||||
|
|
||||||
|
public ClassIO(ReferenceCache referenceCache, SymbolTable symbolTable, SymbolTable fileTable,
|
||||||
|
SymbolTable varTable) {
|
||||||
|
this.symbolTable = symbolTable;
|
||||||
|
programIO = new ProgramIO(referenceCache, symbolTable, fileTable, varTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeClass(OutputStream stream, ClassHolder cls) throws IOException {
|
||||||
|
VarDataOutput output = new VarDataOutput(stream);
|
||||||
|
output.writeUnsigned(cls.getLevel().ordinal());
|
||||||
|
output.writeUnsigned(packModifiers(cls.getModifiers()));
|
||||||
|
output.writeUnsigned(cls.getParent() != null ? symbolTable.lookup(cls.getParent()) + 1 : 0);
|
||||||
|
output.writeUnsigned(cls.getOwnerName() != null ? symbolTable.lookup(cls.getOwnerName()) + 1 : 0);
|
||||||
|
output.writeUnsigned(cls.getInterfaces().size());
|
||||||
|
for (String iface : cls.getInterfaces()) {
|
||||||
|
output.writeUnsigned(symbolTable.lookup(iface));
|
||||||
|
}
|
||||||
|
writeAnnotations(output, cls.getAnnotations());
|
||||||
|
output.writeUnsigned(cls.getFields().size());
|
||||||
|
for (FieldHolder field : cls.getFields()) {
|
||||||
|
writeField(output, field);
|
||||||
|
}
|
||||||
|
output.writeUnsigned(cls.getMethods().size());
|
||||||
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
|
writeMethod(output, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassHolder readClass(InputStream stream, String name) throws IOException {
|
||||||
|
VarDataInput input = new VarDataInput(stream);
|
||||||
|
ClassHolder cls = new ClassHolder(name);
|
||||||
|
cls.setLevel(accessLevels[input.readUnsigned()]);
|
||||||
|
cls.getModifiers().addAll(unpackModifiers(input.readUnsigned()));
|
||||||
|
int parentIndex = input.readUnsigned();
|
||||||
|
cls.setParent(parentIndex > 0 ? symbolTable.at(parentIndex - 1) : null);
|
||||||
|
int ownerIndex = input.readUnsigned();
|
||||||
|
cls.setOwnerName(ownerIndex > 0 ? symbolTable.at(ownerIndex - 1) : null);
|
||||||
|
int ifaceCount = input.readUnsigned();
|
||||||
|
for (int i = 0; i < ifaceCount; ++i) {
|
||||||
|
cls.getInterfaces().add(symbolTable.at(input.readUnsigned()));
|
||||||
|
}
|
||||||
|
readAnnotations(input, cls.getAnnotations());
|
||||||
|
int fieldCount = input.readUnsigned();
|
||||||
|
for (int i = 0; i < fieldCount; ++i) {
|
||||||
|
cls.addField(readField(input));
|
||||||
|
}
|
||||||
|
int methodCount = input.readUnsigned();
|
||||||
|
for (int i = 0; i < methodCount; ++i) {
|
||||||
|
cls.addMethod(readMethod(input));
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeField(VarDataOutput output, FieldHolder field) throws IOException {
|
||||||
|
output.writeUnsigned(symbolTable.lookup(field.getName()));
|
||||||
|
output.writeUnsigned(symbolTable.lookup(field.getType().toString()));
|
||||||
|
output.writeUnsigned(field.getLevel().ordinal());
|
||||||
|
output.writeUnsigned(packModifiers(field.getModifiers()));
|
||||||
|
writeFieldValue(output, field.getInitialValue());
|
||||||
|
writeAnnotations(output, field.getAnnotations());
|
||||||
|
}
|
||||||
|
|
||||||
|
private FieldHolder readField(VarDataInput input) throws IOException {
|
||||||
|
FieldHolder field = new FieldHolder(symbolTable.at(input.readUnsigned()));
|
||||||
|
field.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
|
||||||
|
field.setLevel(accessLevels[input.readUnsigned()]);
|
||||||
|
field.getModifiers().addAll(unpackModifiers(input.readUnsigned()));
|
||||||
|
field.setInitialValue(readFieldValue(input));
|
||||||
|
readAnnotations(input, field.getAnnotations());
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFieldValue(VarDataOutput output, Object value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
output.writeUnsigned(0);
|
||||||
|
} else if (value instanceof Integer) {
|
||||||
|
output.writeUnsigned(1);
|
||||||
|
output.writeUnsigned((Integer) value);
|
||||||
|
} else if (value instanceof Long) {
|
||||||
|
output.writeUnsigned(2);
|
||||||
|
output.writeSigned((Long) value);
|
||||||
|
} else if (value instanceof Float) {
|
||||||
|
output.writeUnsigned(3);
|
||||||
|
output.writeFloat((Float) value);
|
||||||
|
} else if (value instanceof Double) {
|
||||||
|
output.writeUnsigned(4);
|
||||||
|
output.writeDouble((Double) value);
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
output.writeUnsigned(5);
|
||||||
|
output.write((String) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readFieldValue(VarDataInput input) throws IOException {
|
||||||
|
int type = input.readUnsigned();
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
case 1:
|
||||||
|
return input.readSigned();
|
||||||
|
case 2:
|
||||||
|
return input.readSignedLong();
|
||||||
|
case 3:
|
||||||
|
return input.readFloat();
|
||||||
|
case 4:
|
||||||
|
return input.readDouble();
|
||||||
|
case 5:
|
||||||
|
return input.read();
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unexpected field value type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeMethod(VarDataOutput output, MethodHolder method) throws IOException {
|
||||||
|
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
|
||||||
|
output.writeUnsigned(method.getLevel().ordinal());
|
||||||
|
output.writeUnsigned(packModifiers(method.getModifiers()));
|
||||||
|
writeAnnotations(output, method.getAnnotations());
|
||||||
|
|
||||||
|
for (AnnotationContainer parameterAnnotation : method.getParameterAnnotations()) {
|
||||||
|
writeAnnotations(output, parameterAnnotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getAnnotationDefault() != null) {
|
||||||
|
output.writeUnsigned(1);
|
||||||
|
writeAnnotationValue(output, method.getAnnotationDefault());
|
||||||
|
} else {
|
||||||
|
output.writeUnsigned(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getProgram() != null) {
|
||||||
|
output.writeUnsigned(1);
|
||||||
|
programIO.write(method.getProgram(), output);
|
||||||
|
} else {
|
||||||
|
output.writeUnsigned(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHolder readMethod(VarDataInput input) throws IOException {
|
||||||
|
MethodHolder method = new MethodHolder(MethodDescriptor.parse(symbolTable.at(input.readUnsigned())));
|
||||||
|
method.setLevel(accessLevels[input.readUnsigned()]);
|
||||||
|
method.getModifiers().addAll(unpackModifiers(input.readUnsigned()));
|
||||||
|
readAnnotations(input, method.getAnnotations());
|
||||||
|
|
||||||
|
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||||
|
readAnnotations(input, method.parameterAnnotation(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.readUnsigned() != 0) {
|
||||||
|
method.setAnnotationDefault(readAnnotationValue(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.readUnsigned() != 0) {
|
||||||
|
method.setProgram(programIO.read(input));
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAnnotations(VarDataOutput output, AnnotationContainer annotations) throws IOException {
|
||||||
|
List<AnnotationHolder> annotationList = new ArrayList<>();
|
||||||
|
for (AnnotationHolder annot : annotations.all()) {
|
||||||
|
annotationList.add(annot);
|
||||||
|
}
|
||||||
|
output.writeUnsigned(annotationList.size());
|
||||||
|
for (AnnotationHolder annot : annotationList) {
|
||||||
|
writeAnnotation(output, annot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readAnnotations(VarDataInput input, AnnotationContainer annotations) throws IOException {
|
||||||
|
int annotCount = input.readUnsigned();
|
||||||
|
for (int i = 0; i < annotCount; ++i) {
|
||||||
|
AnnotationHolder annot = readAnnotation(input);
|
||||||
|
annotations.add(annot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAnnotation(VarDataOutput output, AnnotationReader annotation) throws IOException {
|
||||||
|
output.writeUnsigned(symbolTable.lookup(annotation.getType()));
|
||||||
|
int fieldCount = 0;
|
||||||
|
for (@SuppressWarnings("unused") String field : annotation.getAvailableFields()) {
|
||||||
|
++fieldCount;
|
||||||
|
}
|
||||||
|
output.writeUnsigned(fieldCount);
|
||||||
|
for (String field : annotation.getAvailableFields()) {
|
||||||
|
output.writeUnsigned(symbolTable.lookup(field));
|
||||||
|
writeAnnotationValue(output, annotation.getValue(field));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationHolder readAnnotation(VarDataInput input) throws IOException {
|
||||||
|
AnnotationHolder annotation = new AnnotationHolder(symbolTable.at(input.readUnsigned()));
|
||||||
|
int valueCount = input.readUnsigned();
|
||||||
|
for (int i = 0; i < valueCount; ++i) {
|
||||||
|
String name = symbolTable.at(input.readUnsigned());
|
||||||
|
AnnotationValue value = readAnnotationValue(input);
|
||||||
|
annotation.getValues().put(name, value);
|
||||||
|
}
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAnnotationValue(VarDataOutput output, AnnotationValue value) throws IOException {
|
||||||
|
output.writeUnsigned(value.getType());
|
||||||
|
switch (value.getType()) {
|
||||||
|
case AnnotationValue.ANNOTATION:
|
||||||
|
writeAnnotation(output, value.getAnnotation());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.BOOLEAN:
|
||||||
|
output.writeUnsigned(value.getBoolean() ? 1 : 0);
|
||||||
|
break;
|
||||||
|
case AnnotationValue.BYTE:
|
||||||
|
output.writeSigned(value.getByte());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.CLASS:
|
||||||
|
output.writeUnsigned(symbolTable.lookup(value.getJavaClass().toString()));
|
||||||
|
break;
|
||||||
|
case AnnotationValue.DOUBLE:
|
||||||
|
output.writeDouble(value.getDouble());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.ENUM:
|
||||||
|
output.writeUnsigned(symbolTable.lookup(value.getEnumValue().getClassName()));
|
||||||
|
output.writeUnsigned(symbolTable.lookup(value.getEnumValue().getFieldName()));
|
||||||
|
break;
|
||||||
|
case AnnotationValue.FLOAT:
|
||||||
|
output.writeFloat(value.getFloat());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.INT:
|
||||||
|
output.writeSigned(value.getInt());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.LIST: {
|
||||||
|
List<AnnotationValue> list = value.getList();
|
||||||
|
output.writeUnsigned(list.size());
|
||||||
|
for (AnnotationValue item : list) {
|
||||||
|
writeAnnotationValue(output, item);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AnnotationValue.LONG:
|
||||||
|
output.writeSigned(value.getLong());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.SHORT:
|
||||||
|
output.writeSigned(value.getShort());
|
||||||
|
break;
|
||||||
|
case AnnotationValue.STRING:
|
||||||
|
output.write(value.getString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnnotationValue readAnnotationValue(VarDataInput input) throws IOException {
|
||||||
|
int type = input.readUnsigned();
|
||||||
|
switch (type) {
|
||||||
|
case AnnotationValue.ANNOTATION:
|
||||||
|
return new AnnotationValue(readAnnotation(input));
|
||||||
|
case AnnotationValue.BOOLEAN:
|
||||||
|
return new AnnotationValue(input.readUnsigned() != 0);
|
||||||
|
case AnnotationValue.BYTE:
|
||||||
|
return new AnnotationValue((byte) input.readSigned());
|
||||||
|
case AnnotationValue.CLASS:
|
||||||
|
return new AnnotationValue(ValueType.parse(symbolTable.at(input.readUnsigned())));
|
||||||
|
case AnnotationValue.DOUBLE:
|
||||||
|
return new AnnotationValue(input.readDouble());
|
||||||
|
case AnnotationValue.ENUM: {
|
||||||
|
String className = symbolTable.at(input.readUnsigned());
|
||||||
|
String fieldName = symbolTable.at(input.readUnsigned());
|
||||||
|
return new AnnotationValue(new FieldReference(className, fieldName));
|
||||||
|
}
|
||||||
|
case AnnotationValue.FLOAT:
|
||||||
|
return new AnnotationValue(input.readFloat());
|
||||||
|
case AnnotationValue.INT:
|
||||||
|
return new AnnotationValue(input.readSigned());
|
||||||
|
case AnnotationValue.LIST: {
|
||||||
|
List<AnnotationValue> list = new ArrayList<>();
|
||||||
|
int sz = input.readUnsigned();
|
||||||
|
for (int i = 0; i < sz; ++i) {
|
||||||
|
list.add(readAnnotationValue(input));
|
||||||
|
}
|
||||||
|
return new AnnotationValue(list);
|
||||||
|
}
|
||||||
|
case AnnotationValue.LONG:
|
||||||
|
return new AnnotationValue(input.readSignedLong());
|
||||||
|
case AnnotationValue.SHORT:
|
||||||
|
return new AnnotationValue((short) input.readSigned());
|
||||||
|
case AnnotationValue.STRING:
|
||||||
|
return new AnnotationValue(input.read());
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Unexpected annotation value type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int packModifiers(Set<ElementModifier> modifiers) {
|
||||||
|
int result = 0;
|
||||||
|
for (ElementModifier modifier : modifiers) {
|
||||||
|
result |= 1 << modifier.ordinal();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<ElementModifier> unpackModifiers(int packed) {
|
||||||
|
Set<ElementModifier> modifiers = EnumSet.noneOf(ElementModifier.class);
|
||||||
|
while (packed != 0) {
|
||||||
|
int n = Integer.numberOfTrailingZeros(packed);
|
||||||
|
packed ^= 1 << n;
|
||||||
|
modifiers.add(elementModifiers[n]);
|
||||||
|
}
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,60 +17,38 @@ 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.DataOutput;
|
|
||||||
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;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.model.AccessLevel;
|
|
||||||
import org.teavm.model.AnnotationContainer;
|
|
||||||
import org.teavm.model.AnnotationHolder;
|
|
||||||
import org.teavm.model.AnnotationReader;
|
|
||||||
import org.teavm.model.AnnotationValue;
|
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassHolderSource;
|
import org.teavm.model.ClassHolderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
|
||||||
import org.teavm.model.FieldHolder;
|
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
import org.teavm.model.MethodDescriptor;
|
|
||||||
import org.teavm.model.MethodHolder;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ReferenceCache;
|
import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
import org.teavm.parsing.ClassDateProvider;
|
import org.teavm.parsing.ClassDateProvider;
|
||||||
|
|
||||||
public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStatus {
|
public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStatus {
|
||||||
private static AccessLevel[] accessLevels = AccessLevel.values();
|
|
||||||
private static ElementModifier[] elementModifiers = ElementModifier.values();
|
|
||||||
private File directory;
|
private File directory;
|
||||||
private SymbolTable symbolTable;
|
|
||||||
private ClassHolderSource innerSource;
|
private ClassHolderSource innerSource;
|
||||||
private ClassDateProvider classDateProvider;
|
private ClassDateProvider classDateProvider;
|
||||||
private Map<String, Item> cache = new LinkedHashMap<>();
|
private Map<String, Item> cache = new LinkedHashMap<>();
|
||||||
private Set<String> newClasses = new HashSet<>();
|
private Set<String> newClasses = new HashSet<>();
|
||||||
private ProgramIO programIO;
|
private ClassIO classIO;
|
||||||
|
|
||||||
public DiskCachedClassHolderSource(File directory, ReferenceCache referenceCache, SymbolTable symbolTable,
|
public DiskCachedClassHolderSource(File directory, ReferenceCache referenceCache, SymbolTable symbolTable,
|
||||||
SymbolTable fileTable, SymbolTable variableTable, ClassHolderSource innerSource,
|
SymbolTable fileTable, SymbolTable variableTable, ClassHolderSource innerSource,
|
||||||
ClassDateProvider classDateProvider) {
|
ClassDateProvider classDateProvider) {
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
this.symbolTable = symbolTable;
|
|
||||||
this.innerSource = innerSource;
|
this.innerSource = innerSource;
|
||||||
this.classDateProvider = classDateProvider;
|
this.classDateProvider = classDateProvider;
|
||||||
programIO = new ProgramIO(referenceCache, symbolTable, fileTable, variableTable);
|
classIO = new ClassIO(referenceCache, symbolTable, fileTable, variableTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,7 +76,7 @@ public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStat
|
||||||
Date classDate = classDateProvider.getModificationDate(name);
|
Date classDate = classDateProvider.getModificationDate(name);
|
||||||
if (classDate != null && classDate.before(new Date(classFile.lastModified()))) {
|
if (classDate != null && classDate.before(new Date(classFile.lastModified()))) {
|
||||||
try (InputStream input = new BufferedInputStream(new FileInputStream(classFile))) {
|
try (InputStream input = new BufferedInputStream(new FileInputStream(classFile))) {
|
||||||
item.cls = readClass(input, name);
|
item.cls = classIO.readClass(input, name);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// We could not access cache file, so let's parse class file
|
// We could not access cache file, so let's parse class file
|
||||||
item.cls = null;
|
item.cls = null;
|
||||||
|
@ -126,313 +104,9 @@ public class DiskCachedClassHolderSource implements ClassHolderSource, CacheStat
|
||||||
File classFile = new File(directory, className.replace('.', '/') + ".teavm-cls");
|
File classFile = new File(directory, className.replace('.', '/') + ".teavm-cls");
|
||||||
classFile.getParentFile().mkdirs();
|
classFile.getParentFile().mkdirs();
|
||||||
try (OutputStream output = new BufferedOutputStream(new FileOutputStream(classFile))) {
|
try (OutputStream output = new BufferedOutputStream(new FileOutputStream(classFile))) {
|
||||||
writeClass(output, item.cls);
|
classIO.writeClass(output, item.cls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeClass(OutputStream stream, ClassHolder cls) throws IOException {
|
|
||||||
DataOutput output = new DataOutputStream(stream);
|
|
||||||
output.writeByte(cls.getLevel().ordinal());
|
|
||||||
output.writeInt(packModifiers(cls.getModifiers()));
|
|
||||||
output.writeInt(cls.getParent() != null ? symbolTable.lookup(cls.getParent()) : -1);
|
|
||||||
output.writeInt(cls.getOwnerName() != null ? symbolTable.lookup(cls.getOwnerName()) : -1);
|
|
||||||
output.writeByte(cls.getInterfaces().size());
|
|
||||||
for (String iface : cls.getInterfaces()) {
|
|
||||||
output.writeInt(symbolTable.lookup(iface));
|
|
||||||
}
|
|
||||||
writeAnnotations(output, cls.getAnnotations());
|
|
||||||
output.writeShort(cls.getFields().size());
|
|
||||||
for (FieldHolder field : cls.getFields()) {
|
|
||||||
writeField(output, field);
|
|
||||||
}
|
|
||||||
output.writeShort(cls.getMethods().size());
|
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
|
||||||
writeMethod(stream, method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClassHolder readClass(InputStream stream, String name) throws IOException {
|
|
||||||
DataInput input = new DataInputStream(stream);
|
|
||||||
ClassHolder cls = new ClassHolder(name);
|
|
||||||
cls.setLevel(accessLevels[input.readByte()]);
|
|
||||||
cls.getModifiers().addAll(unpackModifiers(input.readInt()));
|
|
||||||
int parentIndex = input.readInt();
|
|
||||||
cls.setParent(parentIndex >= 0 ? symbolTable.at(parentIndex) : null);
|
|
||||||
int ownerIndex = input.readInt();
|
|
||||||
cls.setOwnerName(ownerIndex >= 0 ? symbolTable.at(ownerIndex) : null);
|
|
||||||
int ifaceCount = input.readByte();
|
|
||||||
for (int i = 0; i < ifaceCount; ++i) {
|
|
||||||
cls.getInterfaces().add(symbolTable.at(input.readInt()));
|
|
||||||
}
|
|
||||||
readAnnotations(input, cls.getAnnotations());
|
|
||||||
int fieldCount = input.readShort();
|
|
||||||
for (int i = 0; i < fieldCount; ++i) {
|
|
||||||
cls.addField(readField(input));
|
|
||||||
}
|
|
||||||
int methodCount = input.readShort();
|
|
||||||
for (int i = 0; i < methodCount; ++i) {
|
|
||||||
cls.addMethod(readMethod(stream));
|
|
||||||
}
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeField(DataOutput output, FieldHolder field) throws IOException {
|
|
||||||
output.writeInt(symbolTable.lookup(field.getName()));
|
|
||||||
output.writeInt(symbolTable.lookup(field.getType().toString()));
|
|
||||||
output.writeByte(field.getLevel().ordinal());
|
|
||||||
output.writeInt(packModifiers(field.getModifiers()));
|
|
||||||
writeFieldValue(output, field.getInitialValue());
|
|
||||||
writeAnnotations(output, field.getAnnotations());
|
|
||||||
}
|
|
||||||
|
|
||||||
private FieldHolder readField(DataInput input) throws IOException {
|
|
||||||
FieldHolder field = new FieldHolder(symbolTable.at(input.readInt()));
|
|
||||||
field.setType(ValueType.parse(symbolTable.at(input.readInt())));
|
|
||||||
field.setLevel(accessLevels[input.readByte()]);
|
|
||||||
field.getModifiers().addAll(unpackModifiers(input.readInt()));
|
|
||||||
field.setInitialValue(readFieldValue(input));
|
|
||||||
readAnnotations(input, field.getAnnotations());
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeFieldValue(DataOutput output, Object value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
output.writeByte(0);
|
|
||||||
} else if (value instanceof Integer) {
|
|
||||||
output.writeByte(1);
|
|
||||||
output.writeInt((Integer) value);
|
|
||||||
} else if (value instanceof Long) {
|
|
||||||
output.writeByte(2);
|
|
||||||
output.writeLong((Long) value);
|
|
||||||
} else if (value instanceof Float) {
|
|
||||||
output.writeByte(3);
|
|
||||||
output.writeFloat((Float) value);
|
|
||||||
} else if (value instanceof Double) {
|
|
||||||
output.writeByte(4);
|
|
||||||
output.writeDouble((Double) value);
|
|
||||||
} else if (value instanceof String) {
|
|
||||||
output.writeByte(5);
|
|
||||||
output.writeUTF((String) value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object readFieldValue(DataInput input) throws IOException {
|
|
||||||
int type = input.readByte();
|
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
return null;
|
|
||||||
case 1:
|
|
||||||
return input.readInt();
|
|
||||||
case 2:
|
|
||||||
return input.readLong();
|
|
||||||
case 3:
|
|
||||||
return input.readFloat();
|
|
||||||
case 4:
|
|
||||||
return input.readDouble();
|
|
||||||
case 5:
|
|
||||||
return input.readUTF();
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("Unexpected field value type: " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeMethod(OutputStream stream, MethodHolder method) throws IOException {
|
|
||||||
DataOutputStream output = new DataOutputStream(stream);
|
|
||||||
output.writeInt(symbolTable.lookup(method.getDescriptor().toString()));
|
|
||||||
output.writeByte(method.getLevel().ordinal());
|
|
||||||
output.writeInt(packModifiers(method.getModifiers()));
|
|
||||||
writeAnnotations(output, method.getAnnotations());
|
|
||||||
|
|
||||||
for (AnnotationContainer parameterAnnotation : method.getParameterAnnotations()) {
|
|
||||||
writeAnnotations(output, parameterAnnotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method.getAnnotationDefault() != null) {
|
|
||||||
output.writeBoolean(true);
|
|
||||||
writeAnnotationValue(output, method.getAnnotationDefault());
|
|
||||||
} else {
|
|
||||||
output.writeBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method.getProgram() != null) {
|
|
||||||
output.writeBoolean(true);
|
|
||||||
programIO.write(method.getProgram(), output);
|
|
||||||
} else {
|
|
||||||
output.writeBoolean(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodHolder readMethod(InputStream stream) throws IOException {
|
|
||||||
DataInputStream input = new DataInputStream(stream);
|
|
||||||
MethodHolder method = new MethodHolder(MethodDescriptor.parse(symbolTable.at(input.readInt())));
|
|
||||||
method.setLevel(accessLevels[input.readByte()]);
|
|
||||||
method.getModifiers().addAll(unpackModifiers(input.readInt()));
|
|
||||||
readAnnotations(input, method.getAnnotations());
|
|
||||||
|
|
||||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
|
||||||
readAnnotations(input, method.parameterAnnotation(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.readBoolean()) {
|
|
||||||
method.setAnnotationDefault(readAnnotationValue(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasProgram = input.readBoolean();
|
|
||||||
if (hasProgram) {
|
|
||||||
method.setProgram(programIO.read(input));
|
|
||||||
}
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAnnotations(DataOutput output, AnnotationContainer annotations) throws IOException {
|
|
||||||
List<AnnotationHolder> annotationList = new ArrayList<>();
|
|
||||||
for (AnnotationHolder annot : annotations.all()) {
|
|
||||||
annotationList.add(annot);
|
|
||||||
}
|
|
||||||
output.writeShort(annotationList.size());
|
|
||||||
for (AnnotationHolder annot : annotationList) {
|
|
||||||
writeAnnotation(output, annot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readAnnotations(DataInput input, AnnotationContainer annotations) throws IOException {
|
|
||||||
int annotCount = input.readShort();
|
|
||||||
for (int i = 0; i < annotCount; ++i) {
|
|
||||||
AnnotationHolder annot = readAnnotation(input);
|
|
||||||
annotations.add(annot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAnnotation(DataOutput output, AnnotationReader annotation) throws IOException {
|
|
||||||
output.writeInt(symbolTable.lookup(annotation.getType()));
|
|
||||||
int fieldCount = 0;
|
|
||||||
for (@SuppressWarnings("unused") String field : annotation.getAvailableFields()) {
|
|
||||||
++fieldCount;
|
|
||||||
}
|
|
||||||
output.writeShort(fieldCount);
|
|
||||||
for (String field : annotation.getAvailableFields()) {
|
|
||||||
output.writeInt(symbolTable.lookup(field));
|
|
||||||
writeAnnotationValue(output, annotation.getValue(field));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AnnotationHolder readAnnotation(DataInput input) throws IOException {
|
|
||||||
AnnotationHolder annotation = new AnnotationHolder(symbolTable.at(input.readInt()));
|
|
||||||
int valueCount = input.readShort();
|
|
||||||
for (int i = 0; i < valueCount; ++i) {
|
|
||||||
String name = symbolTable.at(input.readInt());
|
|
||||||
AnnotationValue value = readAnnotationValue(input);
|
|
||||||
annotation.getValues().put(name, value);
|
|
||||||
}
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAnnotationValue(DataOutput output, AnnotationValue value) throws IOException {
|
|
||||||
output.writeByte(value.getType());
|
|
||||||
switch (value.getType()) {
|
|
||||||
case AnnotationValue.ANNOTATION:
|
|
||||||
writeAnnotation(output, value.getAnnotation());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.BOOLEAN:
|
|
||||||
output.writeBoolean(value.getBoolean());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.BYTE:
|
|
||||||
output.writeByte(value.getByte());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.CLASS:
|
|
||||||
output.writeInt(symbolTable.lookup(value.getJavaClass().toString()));
|
|
||||||
break;
|
|
||||||
case AnnotationValue.DOUBLE:
|
|
||||||
output.writeDouble(value.getDouble());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.ENUM:
|
|
||||||
output.writeInt(symbolTable.lookup(value.getEnumValue().getClassName()));
|
|
||||||
output.writeInt(symbolTable.lookup(value.getEnumValue().getFieldName()));
|
|
||||||
break;
|
|
||||||
case AnnotationValue.FLOAT:
|
|
||||||
output.writeFloat(value.getFloat());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.INT:
|
|
||||||
output.writeInt(value.getInt());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.LIST: {
|
|
||||||
List<AnnotationValue> list = value.getList();
|
|
||||||
output.writeShort(list.size());
|
|
||||||
for (AnnotationValue item : list) {
|
|
||||||
writeAnnotationValue(output, item);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AnnotationValue.LONG:
|
|
||||||
output.writeLong(value.getLong());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.SHORT:
|
|
||||||
output.writeShort(value.getShort());
|
|
||||||
break;
|
|
||||||
case AnnotationValue.STRING:
|
|
||||||
output.writeUTF(value.getString());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AnnotationValue readAnnotationValue(DataInput input) throws IOException {
|
|
||||||
byte type = input.readByte();
|
|
||||||
switch (type) {
|
|
||||||
case AnnotationValue.ANNOTATION:
|
|
||||||
return new AnnotationValue(readAnnotation(input));
|
|
||||||
case AnnotationValue.BOOLEAN:
|
|
||||||
return new AnnotationValue(input.readBoolean());
|
|
||||||
case AnnotationValue.BYTE:
|
|
||||||
return new AnnotationValue(input.readByte());
|
|
||||||
case AnnotationValue.CLASS:
|
|
||||||
return new AnnotationValue(ValueType.parse(symbolTable.at(input.readInt())));
|
|
||||||
case AnnotationValue.DOUBLE:
|
|
||||||
return new AnnotationValue(input.readDouble());
|
|
||||||
case AnnotationValue.ENUM: {
|
|
||||||
String className = symbolTable.at(input.readInt());
|
|
||||||
String fieldName = symbolTable.at(input.readInt());
|
|
||||||
return new AnnotationValue(new FieldReference(className, fieldName));
|
|
||||||
}
|
|
||||||
case AnnotationValue.FLOAT:
|
|
||||||
return new AnnotationValue(input.readFloat());
|
|
||||||
case AnnotationValue.INT:
|
|
||||||
return new AnnotationValue(input.readInt());
|
|
||||||
case AnnotationValue.LIST: {
|
|
||||||
List<AnnotationValue> list = new ArrayList<>();
|
|
||||||
int sz = input.readShort();
|
|
||||||
for (int i = 0; i < sz; ++i) {
|
|
||||||
list.add(readAnnotationValue(input));
|
|
||||||
}
|
|
||||||
return new AnnotationValue(list);
|
|
||||||
}
|
|
||||||
case AnnotationValue.LONG:
|
|
||||||
return new AnnotationValue(input.readLong());
|
|
||||||
case AnnotationValue.SHORT:
|
|
||||||
return new AnnotationValue(input.readShort());
|
|
||||||
case AnnotationValue.STRING:
|
|
||||||
return new AnnotationValue(input.readUTF());
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("Unexpected annotation value type: " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int packModifiers(Set<ElementModifier> modifiers) {
|
|
||||||
int result = 0;
|
|
||||||
for (ElementModifier modifier : modifiers) {
|
|
||||||
result |= 1 << modifier.ordinal();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<ElementModifier> unpackModifiers(int packed) {
|
|
||||||
Set<ElementModifier> modifiers = EnumSet.noneOf(ElementModifier.class);
|
|
||||||
while (packed != 0) {
|
|
||||||
int n = Integer.numberOfTrailingZeros(packed);
|
|
||||||
packed ^= 1 << n;
|
|
||||||
modifiers.add(elementModifiers[n]);
|
|
||||||
}
|
|
||||||
return modifiers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2018 Alexey Andreev.
|
* Copyright 2019 Alexey Andreev.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,23 +15,35 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.cache;
|
package org.teavm.cache;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.teavm.common.Mapper;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ReferenceCache;
|
||||||
|
|
||||||
public class MemoryCachedClassReaderSource implements ClassReaderSource, CacheStatus {
|
public class MemoryCachedClassReaderSource implements ClassReaderSource, CacheStatus {
|
||||||
private ClassReaderSource underlyingSource;
|
private Map<String, Entry> cache = new HashMap<>();
|
||||||
private final Map<String, Optional<ClassReader>> cache = new HashMap<>();
|
private Mapper<String, ClassHolder> mapper;
|
||||||
|
private ClassIO classIO;
|
||||||
private final Set<String> freshClasses = new HashSet<>();
|
private final Set<String> freshClasses = new HashSet<>();
|
||||||
|
|
||||||
public void setUnderlyingSource(ClassReaderSource underlyingSource) {
|
public MemoryCachedClassReaderSource(ReferenceCache referenceCache, SymbolTable symbolTable,
|
||||||
this.underlyingSource = underlyingSource;
|
SymbolTable fileTable, SymbolTable varTable) {
|
||||||
|
classIO = new ClassIO(referenceCache, symbolTable, fileTable, varTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapper(Mapper<String, ClassHolder> mapper) {
|
||||||
|
this.mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,12 +58,37 @@ public class MemoryCachedClassReaderSource implements ClassReaderSource, CacheSt
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassReader get(String name) {
|
public ClassReader get(String name) {
|
||||||
return cache.computeIfAbsent(name, key -> {
|
Entry entry = cache.computeIfAbsent(name, className -> {
|
||||||
if (underlyingSource == null) {
|
ClassHolder cls = mapper.map(name);
|
||||||
return Optional.empty();
|
Entry en = new Entry();
|
||||||
|
if (cls != null) {
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
classIO.writeClass(output, cls);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return Optional.ofNullable(underlyingSource.get(key));
|
en.data = output.toByteArray();
|
||||||
}).orElse(null);
|
en.reader = new WeakReference<>(cls);
|
||||||
|
}
|
||||||
|
return en;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entry.data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassReader cls = entry.reader.get();
|
||||||
|
if (cls == null) {
|
||||||
|
ByteArrayInputStream input = new ByteArrayInputStream(entry.data);
|
||||||
|
try {
|
||||||
|
cls = classIO.readClass(input, name);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
entry.reader = new WeakReference<>(cls);
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commit() {
|
public void commit() {
|
||||||
|
@ -67,4 +104,9 @@ public class MemoryCachedClassReaderSource implements ClassReaderSource, CacheSt
|
||||||
cache.clear();
|
cache.clear();
|
||||||
freshClasses.clear();
|
freshClasses.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Entry {
|
||||||
|
byte[] data;
|
||||||
|
WeakReference<ClassReader> reader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,10 @@ public class ProgramIO {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(Program program, OutputStream output) throws IOException {
|
public void write(Program program, OutputStream output) throws IOException {
|
||||||
VarDataOutput data = new VarDataOutput(output);
|
write(program, new VarDataOutput(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(Program program, VarDataOutput data) throws IOException {
|
||||||
data.writeUnsigned(program.variableCount());
|
data.writeUnsigned(program.variableCount());
|
||||||
data.writeUnsigned(program.basicBlockCount());
|
data.writeUnsigned(program.basicBlockCount());
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
@ -162,7 +165,10 @@ public class ProgramIO {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Program read(InputStream input) throws IOException {
|
public Program read(InputStream input) throws IOException {
|
||||||
VarDataInput data = new VarDataInput(input);
|
return read(new VarDataInput(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Program read(VarDataInput data) throws IOException {
|
||||||
Program program = new Program();
|
Program program = new Program();
|
||||||
int varCount = data.readUnsigned();
|
int varCount = data.readUnsigned();
|
||||||
int basicBlockCount = data.readUnsigned();
|
int basicBlockCount = data.readUnsigned();
|
||||||
|
@ -200,8 +206,8 @@ public class ProgramIO {
|
||||||
for (int j = 0; j < tryCatchCount; ++j) {
|
for (int j = 0; j < tryCatchCount; ++j) {
|
||||||
TryCatchBlock tryCatch = new TryCatchBlock();
|
TryCatchBlock tryCatch = new TryCatchBlock();
|
||||||
int typeIndex = data.readUnsigned();
|
int typeIndex = data.readUnsigned();
|
||||||
if (typeIndex >= 0) {
|
if (typeIndex > 0) {
|
||||||
tryCatch.setExceptionType(symbolTable.at(typeIndex));
|
tryCatch.setExceptionType(symbolTable.at(typeIndex - 1));
|
||||||
}
|
}
|
||||||
tryCatch.setHandler(program.basicBlockAt(data.readUnsigned()));
|
tryCatch.setHandler(program.basicBlockAt(data.readUnsigned()));
|
||||||
|
|
||||||
|
@ -635,8 +641,8 @@ public class ProgramIO {
|
||||||
public void visit(InvokeDynamicInstruction insn) {
|
public void visit(InvokeDynamicInstruction insn) {
|
||||||
try {
|
try {
|
||||||
output.writeUnsigned(81);
|
output.writeUnsigned(81);
|
||||||
output.writeUnsigned(insn.getReceiver() != null ? insn.getReceiver().getIndex() : -1);
|
output.writeUnsigned(insn.getReceiver() != null ? insn.getReceiver().getIndex() + 1 : 0);
|
||||||
output.writeUnsigned(insn.getInstance() != null ? insn.getInstance().getIndex() : -1);
|
output.writeUnsigned(insn.getInstance() != null ? insn.getInstance().getIndex() + 1 : 0);
|
||||||
output.writeUnsigned(symbolTable.lookup(insn.getMethod().toString()));
|
output.writeUnsigned(symbolTable.lookup(insn.getMethod().toString()));
|
||||||
for (int i = 0; i < insn.getArguments().size(); ++i) {
|
for (int i = 0; i < insn.getArguments().size(); ++i) {
|
||||||
output.writeUnsigned(insn.getArguments().get(i).getIndex());
|
output.writeUnsigned(insn.getArguments().get(i).getIndex());
|
||||||
|
|
|
@ -759,6 +759,8 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
|
||||||
classSource.cleanup();
|
classSource.cleanup();
|
||||||
agent.cleanup();
|
agent.cleanup();
|
||||||
listeners.clear();
|
listeners.clear();
|
||||||
|
unprocessedClassSource = null;
|
||||||
|
classSource.innerHierarchy = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanupTypes() {
|
public void cleanupTypes() {
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.teavm.model.util.ModelUtils;
|
||||||
|
|
||||||
class DependencyClassSource implements ClassHolderSource {
|
class DependencyClassSource implements ClassHolderSource {
|
||||||
private ClassReaderSource innerSource;
|
private ClassReaderSource innerSource;
|
||||||
private ClassHierarchy innerHierarchy;
|
ClassHierarchy innerHierarchy;
|
||||||
private Diagnostics diagnostics;
|
private Diagnostics diagnostics;
|
||||||
private IncrementalDependencyRegistration dependencyRegistration;
|
private IncrementalDependencyRegistration dependencyRegistration;
|
||||||
private Map<String, ClassHolder> generatedClasses = new LinkedHashMap<>();
|
private Map<String, ClassHolder> generatedClasses = new LinkedHashMap<>();
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.model;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.teavm.common.Mapper;
|
||||||
import org.teavm.model.optimization.GlobalValueNumbering;
|
import org.teavm.model.optimization.GlobalValueNumbering;
|
||||||
import org.teavm.model.optimization.UnusedVariableElimination;
|
import org.teavm.model.optimization.UnusedVariableElimination;
|
||||||
|
|
||||||
|
@ -32,16 +33,25 @@ public class PreOptimizingClassHolderSource implements ClassHolderSource {
|
||||||
public ClassHolder get(String name) {
|
public ClassHolder get(String name) {
|
||||||
ClassHolder cls = cache.get(name);
|
ClassHolder cls = cache.get(name);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
cls = innerClassSource.get(name);
|
cls = optimize(innerClassSource::get, name);
|
||||||
if (cls == null) {
|
if (cls == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache.put(name, cls);
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassHolder optimize(Mapper<String, ClassHolder> innerSource, String name) {
|
||||||
|
ClassHolder cls = innerSource.map(name);
|
||||||
|
if (cls == null) {
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
new GlobalValueNumbering(true).optimize(method.getProgram());
|
new GlobalValueNumbering(true).optimize(method.getProgram());
|
||||||
new UnusedVariableElimination().optimize(method, method.getProgram());
|
new UnusedVariableElimination().optimize(method, method.getProgram());
|
||||||
}
|
}
|
||||||
cache.put(name, cls);
|
|
||||||
}
|
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -609,9 +609,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
changed |= optimization.optimize(context, optimizedProgram);
|
changed |= optimization.optimize(context, optimizedProgram);
|
||||||
} catch (Exception | AssertionError e) {
|
} catch (Exception | AssertionError e) {
|
||||||
ListingBuilder listingBuilder = new ListingBuilder();
|
ListingBuilder listingBuilder = new ListingBuilder();
|
||||||
|
try {
|
||||||
String listing = listingBuilder.buildListing(optimizedProgram, "");
|
String listing = listingBuilder.buildListing(optimizedProgram, "");
|
||||||
System.err.println("Error optimizing program for method " + method.getReference()
|
System.err.println("Error optimizing program for method " + method.getReference()
|
||||||
+ ":\n" + listing);
|
+ ":\n" + listing);
|
||||||
|
} catch (RuntimeException e2) {
|
||||||
|
System.err.println("Error optimizing program for method " + method.getReference());
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,13 +71,17 @@ import org.teavm.cache.InMemoryMethodNodeCache;
|
||||||
import org.teavm.cache.InMemoryProgramCache;
|
import org.teavm.cache.InMemoryProgramCache;
|
||||||
import org.teavm.cache.InMemorySymbolTable;
|
import org.teavm.cache.InMemorySymbolTable;
|
||||||
import org.teavm.cache.MemoryCachedClassReaderSource;
|
import org.teavm.cache.MemoryCachedClassReaderSource;
|
||||||
|
import org.teavm.common.Mapper;
|
||||||
import org.teavm.debugging.information.DebugInformation;
|
import org.teavm.debugging.information.DebugInformation;
|
||||||
import org.teavm.debugging.information.DebugInformationBuilder;
|
import org.teavm.debugging.information.DebugInformationBuilder;
|
||||||
import org.teavm.dependency.FastDependencyAnalyzer;
|
import org.teavm.dependency.FastDependencyAnalyzer;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||||
import org.teavm.model.ReferenceCache;
|
import org.teavm.model.ReferenceCache;
|
||||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
import org.teavm.parsing.ClasspathResourceMapper;
|
||||||
|
import org.teavm.parsing.resource.ClasspathResourceReader;
|
||||||
|
import org.teavm.parsing.resource.ResourceClassHolderMapper;
|
||||||
import org.teavm.tooling.EmptyTeaVMToolLog;
|
import org.teavm.tooling.EmptyTeaVMToolLog;
|
||||||
import org.teavm.tooling.TeaVMProblemRenderer;
|
import org.teavm.tooling.TeaVMProblemRenderer;
|
||||||
import org.teavm.tooling.TeaVMToolLog;
|
import org.teavm.tooling.TeaVMToolLog;
|
||||||
|
@ -709,7 +713,8 @@ public class CodeServlet extends HttpServlet {
|
||||||
private void initBuilder() throws IOException {
|
private void initBuilder() throws IOException {
|
||||||
watcher = new FileSystemWatcher(classPath);
|
watcher = new FileSystemWatcher(classPath);
|
||||||
|
|
||||||
classSource = new MemoryCachedClassReaderSource();
|
classSource = new MemoryCachedClassReaderSource(referenceCache, symbolTable, fileSymbolTable,
|
||||||
|
variableSymbolTable);
|
||||||
astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
|
astCache = new InMemoryMethodNodeCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
|
||||||
programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
|
programCache = new InMemoryProgramCache(referenceCache, symbolTable, fileSymbolTable, variableSymbolTable);
|
||||||
}
|
}
|
||||||
|
@ -738,8 +743,11 @@ public class CodeServlet extends HttpServlet {
|
||||||
|
|
||||||
DebugInformationBuilder debugInformationBuilder = new DebugInformationBuilder(referenceCache);
|
DebugInformationBuilder debugInformationBuilder = new DebugInformationBuilder(referenceCache);
|
||||||
ClassLoader classLoader = initClassLoader();
|
ClassLoader classLoader = initClassLoader();
|
||||||
classSource.setUnderlyingSource(new PreOptimizingClassHolderSource(
|
ClasspathResourceReader reader = new ClasspathResourceReader(classLoader);
|
||||||
new ClasspathClassHolderSource(classLoader, referenceCache)));
|
ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader, referenceCache);
|
||||||
|
Mapper<String, ClassHolder> classPathMapper = new ClasspathResourceMapper(classLoader, referenceCache,
|
||||||
|
rawMapper);
|
||||||
|
classSource.setMapper(name -> PreOptimizingClassHolderSource.optimize(classPathMapper, name));
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
JavaScriptTarget jsTarget = new JavaScriptTarget();
|
JavaScriptTarget jsTarget = new JavaScriptTarget();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user