Decrease memory consumption

This commit is contained in:
Alexey Andreev 2018-12-29 19:02:03 +03:00
parent 97a1db1b79
commit f589b0035a
29 changed files with 298 additions and 255 deletions

View File

@ -70,7 +70,7 @@ public class JCLPlugin implements TeaVMPlugin {
ValueType.arrayOf(ValueType.object("java.lang.Object")), ValueType.arrayOf(ValueType.object("java.lang.Object")),
ValueType.object("java.lang.invoke.CallSite")), lms); ValueType.object("java.lang.invoke.CallSite")), lms);
StringConcatFactorySubstritutor stringConcatSubstitutor = new StringConcatFactorySubstritutor(); StringConcatFactorySubstitutor stringConcatSubstitutor = new StringConcatFactorySubstitutor();
host.add(new MethodReference("java.lang.invoke.StringConcatFactory", "makeConcat", host.add(new MethodReference("java.lang.invoke.StringConcatFactory", "makeConcat",
ValueType.object("java.lang.invoke.MethodHandles$Lookup"), ValueType.object("java.lang.String"), ValueType.object("java.lang.invoke.MethodHandles$Lookup"), ValueType.object("java.lang.String"),
ValueType.object("java.lang.invoke.MethodType"), ValueType.object("java.lang.invoke.CallSite")), ValueType.object("java.lang.invoke.MethodType"), ValueType.object("java.lang.invoke.CallSite")),

View File

@ -18,12 +18,14 @@ package org.teavm.classlib.impl;
import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DynamicCallSite; import org.teavm.dependency.DynamicCallSite;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ReferenceCache;
import org.teavm.model.RuntimeConstant; import org.teavm.model.RuntimeConstant;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter; import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter; import org.teavm.model.emit.ValueEmitter;
public class StringConcatFactorySubstritutor implements BootstrapMethodSubstitutor { public class StringConcatFactorySubstitutor implements BootstrapMethodSubstitutor {
private ReferenceCache referenceCache = new ReferenceCache();
private static final String STRING_BUILDER = "java.lang.StringBuilder"; private static final String STRING_BUILDER = "java.lang.StringBuilder";
private static final char VALUE_ARGUMENT = '\1'; private static final char VALUE_ARGUMENT = '\1';
private static final char CONST_ARGUMENT = '\2'; private static final char CONST_ARGUMENT = '\2';
@ -100,7 +102,8 @@ public class StringConcatFactorySubstritutor implements BootstrapMethodSubstitut
if (!(type instanceof ValueType.Primitive)) { if (!(type instanceof ValueType.Primitive)) {
type = ValueType.object("java.lang.Object"); type = ValueType.object("java.lang.Object");
} }
MethodReference method = new MethodReference(STRING_BUILDER, "append", type, ValueType.object(STRING_BUILDER)); MethodReference method = referenceCache.getCached(new MethodReference(STRING_BUILDER, "append", type,
ValueType.object(STRING_BUILDER)));
return sb.invokeSpecial(method, argument); return sb.invokeSpecial(method, argument);
} }

View File

@ -162,7 +162,7 @@ public class ProgramIO {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setRegister(data.readShort()); var.setRegister(data.readShort());
var.setDebugName(data.readUTF()); var.setDebugName(referenceCache.getCached(data.readUTF()));
if (var.getDebugName().isEmpty()) { if (var.getDebugName().isEmpty()) {
var.setDebugName(null); var.setDebugName(null);
} }

View File

@ -35,4 +35,8 @@ public abstract class AbstractDependencyListener implements DependencyListener {
@Override @Override
public void completing(DependencyAgent agent) { public void completing(DependencyAgent agent) {
} }
@Override
public void complete() {
}
} }

View File

@ -135,4 +135,8 @@ public class DependencyAgent implements DependencyInfo, ServiceRepository {
public IncrementalDependencyRegistration getIncrementalCache() { public IncrementalDependencyRegistration getIncrementalCache() {
return analyzer.incrementalCache; return analyzer.incrementalCache;
} }
void cleanup() {
analyzer = null;
}
} }

View File

@ -700,6 +700,10 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
} }
} }
for (DependencyListener listener : listeners) {
listener.complete();
}
if (dependencyReport) { if (dependencyReport) {
reportDependencies(); reportDependencies();
} }
@ -745,6 +749,8 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
} }
allNodes.clear(); allNodes.clear();
classSource.cleanup();
agent.cleanup();
} }
static class ReportEntry { static class ReportEntry {
@ -903,7 +909,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo {
splitter.fixProgram(); splitter.fixProgram();
} }
class IncrementalCache implements IncrementalDependencyProvider, IncrementalDependencyRegistration { static class IncrementalCache implements IncrementalDependencyProvider, IncrementalDependencyRegistration {
private final String[] emptyArray = new String[0]; private final String[] emptyArray = new String[0];
private Map<String, IncrementalItem> classes = new HashMap<>(); private Map<String, IncrementalItem> classes = new HashMap<>();
private Map<MethodReference, IncrementalItem> methods = new HashMap<>(); private Map<MethodReference, IncrementalItem> methods = new HashMap<>();

View File

@ -105,6 +105,10 @@ class DependencyClassSource implements ClassHolderSource {
transformers.add(transformer); transformers.add(transformer);
} }
public void cleanup() {
transformers.clear();
}
final ClassHolderTransformerContext transformContext = new ClassHolderTransformerContext() { final ClassHolderTransformerContext transformContext = new ClassHolderTransformerContext() {
@Override @Override
public ClassHierarchy getHierarchy() { public ClassHierarchy getHierarchy() {

View File

@ -25,4 +25,6 @@ public interface DependencyListener {
void fieldReached(DependencyAgent agent, FieldDependency field); void fieldReached(DependencyAgent agent, FieldDependency field);
void completing(DependencyAgent agent); void completing(DependencyAgent agent);
void complete();
} }

View File

@ -15,13 +15,17 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class AnnotationContainer implements AnnotationContainerReader { public class AnnotationContainer implements AnnotationContainerReader {
private Map<String, AnnotationHolder> annotations = new LinkedHashMap<>(); private Map<String, AnnotationHolder> annotations;
public void add(AnnotationHolder annotation) { public void add(AnnotationHolder annotation) {
if (annotations == null) {
annotations = new LinkedHashMap<>();
}
if (annotations.containsKey(annotation.getType())) { if (annotations.containsKey(annotation.getType())) {
throw new IllegalArgumentException("Annotation of type " + annotation.getType() + " is already there"); throw new IllegalArgumentException("Annotation of type " + annotation.getType() + " is already there");
} }
@ -30,7 +34,7 @@ public class AnnotationContainer implements AnnotationContainerReader {
@Override @Override
public AnnotationHolder get(String type) { public AnnotationHolder get(String type) {
return annotations.get(type); return annotations != null ? annotations.get(type) : null;
} }
public void remove(AnnotationHolder annotation) { public void remove(AnnotationHolder annotation) {
@ -42,11 +46,13 @@ public class AnnotationContainer implements AnnotationContainerReader {
} }
public void remove(String type) { public void remove(String type) {
if (annotations != null) {
annotations.remove(type); annotations.remove(type);
} }
}
@Override @Override
public Iterable<AnnotationHolder> all() { public Iterable<AnnotationHolder> all() {
return annotations.values(); return annotations != null ? annotations.values() : Collections.emptyList();
} }
} }

View File

@ -17,7 +17,6 @@ package org.teavm.model;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -28,8 +27,8 @@ import org.teavm.model.util.TransitionExtractor;
public class BasicBlock implements BasicBlockReader, Iterable<Instruction> { public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
private Program program; private Program program;
private int index; private int index;
private List<Phi> phis = new ArrayList<>(); private List<Phi> phis;
private List<TryCatchBlock> tryCatchBlocks = new ArrayList<>(); private List<TryCatchBlock> tryCatchBlocks;
private Variable exceptionVariable; private Variable exceptionVariable;
private String label; private String label;
Instruction firstInstruction; Instruction firstInstruction;
@ -172,12 +171,15 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
private List<Phi> safePhis = new AbstractList<Phi>() { private List<Phi> safePhis = new AbstractList<Phi>() {
@Override @Override
public Phi get(int index) { public Phi get(int index) {
if (phis == null) {
throw new IndexOutOfBoundsException();
}
return phis.get(index); return phis.get(index);
} }
@Override @Override
public int size() { public int size() {
return phis.size(); return phis != null ? phis.size() : 0;
} }
@Override @Override
@ -186,6 +188,9 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
throw new IllegalArgumentException("This phi is already in some basic block"); throw new IllegalArgumentException("This phi is already in some basic block");
} }
e.setBasicBlock(BasicBlock.this); e.setBasicBlock(BasicBlock.this);
if (phis == null) {
phis = new ArrayList<>(1);
}
phis.add(index, e); phis.add(index, e);
} }
@ -194,6 +199,9 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
if (element.getBasicBlock() != null) { if (element.getBasicBlock() != null) {
throw new IllegalArgumentException("This phi is already in some basic block"); throw new IllegalArgumentException("This phi is already in some basic block");
} }
if (phis == null) {
phis = new ArrayList<>(1);
}
Phi oldPhi = phis.get(index); Phi oldPhi = phis.get(index);
oldPhi.setBasicBlock(null); oldPhi.setBasicBlock(null);
element.setBasicBlock(BasicBlock.this); element.setBasicBlock(BasicBlock.this);
@ -202,6 +210,9 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
@Override @Override
public Phi remove(int index) { public Phi remove(int index) {
if (phis == null) {
throw new IndexOutOfBoundsException();
}
Phi phi = phis.remove(index); Phi phi = phis.remove(index);
phi.setBasicBlock(null); phi.setBasicBlock(null);
return phi; return phi;
@ -209,10 +220,13 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
@Override @Override
public void clear() { public void clear() {
if (phis == null) {
return;
}
for (Phi phi : phis) { for (Phi phi : phis) {
phi.setBasicBlock(null); phi.setBasicBlock(null);
} }
phis.clear(); phis = null;
} }
}; };
@ -220,7 +234,20 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
return safePhis; return safePhis;
} }
private List<Phi> immutablePhis = Collections.unmodifiableList(phis); private List<Phi> immutablePhis = new AbstractList<Phi>() {
@Override
public Phi get(int index) {
if (phis == null) {
throw new IndexOutOfBoundsException();
}
return phis.get(index);
}
@Override
public int size() {
return phis != null ? phis.size() : 0;
}
};
@Override @Override
public List<? extends PhiReader> readPhis() { public List<? extends PhiReader> readPhis() {
@ -299,7 +326,20 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
} }
} }
private List<TryCatchBlock> immutableTryCatchBlocks = Collections.unmodifiableList(tryCatchBlocks); private List<TryCatchBlock> immutableTryCatchBlocks = new AbstractList<TryCatchBlock>() {
@Override
public TryCatchBlock get(int index) {
if (tryCatchBlocks == null) {
throw new IndexOutOfBoundsException();
}
return tryCatchBlocks.get(index);
}
@Override
public int size() {
return tryCatchBlocks != null ? tryCatchBlocks.size() : 0;
}
};
@Override @Override
public List<TryCatchBlock> readTryCatchBlocks() { public List<TryCatchBlock> readTryCatchBlocks() {
@ -307,25 +347,43 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
} }
private List<TryCatchBlock> safeTryCatchBlocks = new AbstractList<TryCatchBlock>() { private List<TryCatchBlock> safeTryCatchBlocks = new AbstractList<TryCatchBlock>() {
@Override public TryCatchBlock get(int index) { @Override
public TryCatchBlock get(int index) {
if (tryCatchBlocks == null) {
throw new IndexOutOfBoundsException();
}
return tryCatchBlocks.get(index); return tryCatchBlocks.get(index);
} }
@Override public int size() {
return tryCatchBlocks.size(); @Override
public int size() {
return tryCatchBlocks != null ? tryCatchBlocks.size() : 0;
} }
@Override public void add(int index, TryCatchBlock element) {
@Override
public void add(int index, TryCatchBlock element) {
if (element.protectedBlock == BasicBlock.this) { if (element.protectedBlock == BasicBlock.this) {
throw new IllegalStateException("This try/catch block is already added to basic block"); throw new IllegalStateException("This try/catch block is already added to basic block");
} }
element.protectedBlock = BasicBlock.this; element.protectedBlock = BasicBlock.this;
if (tryCatchBlocks == null) {
tryCatchBlocks = new ArrayList<>(1);
}
tryCatchBlocks.add(index, element); tryCatchBlocks.add(index, element);
} }
@Override public TryCatchBlock remove(int index) {
@Override
public TryCatchBlock remove(int index) {
if (tryCatchBlocks == null) {
throw new IndexOutOfBoundsException();
}
TryCatchBlock tryCatch = tryCatchBlocks.remove(index); TryCatchBlock tryCatch = tryCatchBlocks.remove(index);
tryCatch.protectedBlock = null; tryCatch.protectedBlock = null;
return tryCatch; return tryCatch;
} }
@Override public TryCatchBlock set(int index, TryCatchBlock element) {
@Override
public TryCatchBlock set(int index, TryCatchBlock element) {
TryCatchBlock oldTryCatch = tryCatchBlocks.get(index); TryCatchBlock oldTryCatch = tryCatchBlocks.get(index);
if (oldTryCatch == element) { if (oldTryCatch == element) {
return oldTryCatch; return oldTryCatch;
@ -335,14 +393,22 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
} }
oldTryCatch.protectedBlock = null; oldTryCatch.protectedBlock = null;
element.protectedBlock = BasicBlock.this; element.protectedBlock = BasicBlock.this;
if (tryCatchBlocks == null) {
tryCatchBlocks = new ArrayList<>(1);
}
tryCatchBlocks.set(index, element); tryCatchBlocks.set(index, element);
return oldTryCatch; return oldTryCatch;
} }
@Override public void clear() {
@Override
public void clear() {
if (tryCatchBlocks == null) {
return;
}
for (TryCatchBlock tryCatch : tryCatchBlocks) { for (TryCatchBlock tryCatch : tryCatchBlocks) {
tryCatch.protectedBlock = null; tryCatch.protectedBlock = null;
} }
tryCatchBlocks.clear(); tryCatchBlocks = null;
} }
}; };

View File

@ -19,6 +19,7 @@ public class FieldHolder extends MemberHolder implements FieldReader {
private ValueType type; private ValueType type;
private Object initialValue; private Object initialValue;
private ClassHolder owner; private ClassHolder owner;
private FieldReference reference;
public FieldHolder(String name) { public FieldHolder(String name) {
super(name); super(name);
@ -48,6 +49,7 @@ public class FieldHolder extends MemberHolder implements FieldReader {
void setOwner(ClassHolder owner) { void setOwner(ClassHolder owner) {
this.owner = owner; this.owner = owner;
reference = null;
} }
@Override @Override
@ -57,6 +59,16 @@ public class FieldHolder extends MemberHolder implements FieldReader {
@Override @Override
public FieldReference getReference() { public FieldReference getReference() {
return new FieldReference(getOwnerName(), getName()); if (reference == null && owner != null) {
reference = new FieldReference(getOwnerName(), getName());
}
return reference;
}
public void updateReference(ReferenceCache cache) {
FieldReference reference = getReference();
if (reference != null) {
this.reference = cache.getCached(reference);
}
} }
} }

View File

@ -101,6 +101,13 @@ public class MethodHolder extends MemberHolder implements MethodReader {
return reference; return reference;
} }
public void updateReference(ReferenceCache cache) {
MethodReference reference = getReference();
if (reference != null) {
this.reference = cache.getCached(reference);
}
}
@Override @Override
public Program getProgram() { public Program getProgram() {
return program; return program;

View File

@ -23,7 +23,7 @@ import java.util.List;
public class Phi implements PhiReader { public class Phi implements PhiReader {
private BasicBlock basicBlock; private BasicBlock basicBlock;
private Variable receiver; private Variable receiver;
private List<Incoming> incomings = new ArrayList<>(); private List<Incoming> incomings = new ArrayList<>(2);
@Override @Override
public BasicBlock getBasicBlock() { public BasicBlock getBasicBlock() {

View File

@ -19,7 +19,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Program implements ProgramReader { public class Program implements ProgramReader {
private List<BasicBlock> basicBlocks = new ArrayList<>(); private List<BasicBlock> basicBlocks = new ArrayList<>(2);
private List<Variable> variables = new ArrayList<>(); private List<Variable> variables = new ArrayList<>();
private MethodHolder method; private MethodHolder method;
private boolean packed; private boolean packed;

View File

@ -23,7 +23,7 @@ public class ReferenceCache {
private Map<FieldReference, FieldReference> fieldRefenceCache = new HashMap<>(); private Map<FieldReference, FieldReference> fieldRefenceCache = new HashMap<>();
private Map<MethodDescriptor, MethodDescriptor> descriptorCache = new HashMap<>(); private Map<MethodDescriptor, MethodDescriptor> descriptorCache = new HashMap<>();
private Map<ValueType, ValueType> valueTypeCache = new HashMap<>(); private Map<ValueType, ValueType> valueTypeCache = new HashMap<>();
private Map<String, String> classCache = new HashMap<>(); private Map<String, String> stringCache = new HashMap<>();
private Map<String, MethodReference> referenceParseCache = new HashMap<>(); private Map<String, MethodReference> referenceParseCache = new HashMap<>();
private Map<String, MethodDescriptor> descriptorParseCache = new HashMap<>(); private Map<String, MethodDescriptor> descriptorParseCache = new HashMap<>();
private Map<String, ValueType> valueTypeParseCache = new HashMap<>(); private Map<String, ValueType> valueTypeParseCache = new HashMap<>();
@ -103,11 +103,11 @@ public class ReferenceCache {
return result; return result;
} }
public String getCached(String className) { public String getCached(String s) {
String result = classCache.get(className); String result = stringCache.get(s);
if (result == null) { if (result == null) {
result = className; result = s;
classCache.put(result, result); stringCache.put(result, result);
} }
return result; return result;
} }

View File

@ -25,7 +25,7 @@ public class InvokeInstruction extends Instruction {
private InvocationType type; private InvocationType type;
private MethodReference method; private MethodReference method;
private Variable instance; private Variable instance;
private List<Variable> arguments = new ArrayList<>(); private List<Variable> arguments = new ArrayList<>(1);
private Variable receiver; private Variable receiver;
public InvocationType getType() { public InvocationType getType() {

View File

@ -35,51 +35,28 @@ import org.teavm.model.MethodHandle;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ReferenceCache;
import org.teavm.model.RuntimeConstant; import org.teavm.model.RuntimeConstant;
import org.teavm.model.TryCatchBlock; import org.teavm.model.TryCatchBlock;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.AbstractInstructionVisitor;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction; import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction; import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.CloneArrayInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction; import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction; import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction; import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.GetFieldInstruction; import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InitClassInstruction; import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InstructionVisitor;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction; import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
import org.teavm.model.instructions.MonitorExitInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction; import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction;
public class ClassRefsRenamer implements InstructionVisitor { public class ClassRefsRenamer extends AbstractInstructionVisitor {
private ReferenceCache referenceCache;
private Mapper<String, String> classNameMapper; private Mapper<String, String> classNameMapper;
public ClassRefsRenamer(Mapper<String, String> classNameMapper) { public ClassRefsRenamer(ReferenceCache referenceCache, Mapper<String, String> classNameMapper) {
this.referenceCache = referenceCache;
this.classNameMapper = classNameMapper; this.classNameMapper = classNameMapper;
} }
@ -153,10 +130,10 @@ public class ClassRefsRenamer implements InstructionVisitor {
private ValueType rename(ValueType type) { private ValueType rename(ValueType type) {
if (type instanceof ValueType.Array) { if (type instanceof ValueType.Array) {
ValueType itemType = ((ValueType.Array) type).getItemType(); ValueType itemType = ((ValueType.Array) type).getItemType();
return ValueType.arrayOf(rename(itemType)); return referenceCache.getCached(ValueType.arrayOf(rename(itemType)));
} else if (type instanceof ValueType.Object) { } else if (type instanceof ValueType.Object) {
String className = ((ValueType.Object) type).getClassName(); String className = ((ValueType.Object) type).getClassName();
return ValueType.object(classNameMapper.map(className)); return referenceCache.getCached(ValueType.object(classNameMapper.map(className)));
} else { } else {
return type; return type;
} }
@ -245,88 +222,16 @@ public class ClassRefsRenamer implements InstructionVisitor {
} }
} }
@Override
public void visit(EmptyInstruction insn) {
}
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
insn.setConstant(rename(insn.getConstant())); insn.setConstant(rename(insn.getConstant()));
} }
@Override
public void visit(NullConstantInstruction insn) {
}
@Override
public void visit(IntegerConstantInstruction insn) {
}
@Override
public void visit(LongConstantInstruction insn) {
}
@Override
public void visit(FloatConstantInstruction insn) {
}
@Override
public void visit(DoubleConstantInstruction insn) {
}
@Override
public void visit(StringConstantInstruction insn) {
}
@Override
public void visit(BinaryInstruction insn) {
}
@Override
public void visit(NegateInstruction insn) {
}
@Override
public void visit(AssignInstruction insn) {
}
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
insn.setTargetType(rename(insn.getTargetType())); insn.setTargetType(rename(insn.getTargetType()));
} }
@Override
public void visit(CastNumberInstruction insn) {
}
@Override
public void visit(CastIntegerInstruction insn) {
}
@Override
public void visit(BranchingInstruction insn) {
}
@Override
public void visit(BinaryBranchingInstruction insn) {
}
@Override
public void visit(JumpInstruction insn) {
}
@Override
public void visit(SwitchInstruction insn) {
}
@Override
public void visit(ExitInstruction insn) {
}
@Override
public void visit(RaiseInstruction insn) {
}
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void visit(ConstructArrayInstruction insn) {
insn.setItemType(rename(insn.getItemType())); insn.setItemType(rename(insn.getItemType()));
@ -345,43 +250,33 @@ public class ClassRefsRenamer implements InstructionVisitor {
@Override @Override
public void visit(GetFieldInstruction insn) { public void visit(GetFieldInstruction insn) {
String className = classNameMapper.map(insn.getField().getClassName()); String className = classNameMapper.map(insn.getField().getClassName());
insn.setField(new FieldReference(className, insn.getField().getFieldName())); insn.setField(referenceCache.getCached(new FieldReference(className, insn.getField().getFieldName())));
} }
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
String className = classNameMapper.map(insn.getField().getClassName()); String className = classNameMapper.map(insn.getField().getClassName());
insn.setField(new FieldReference(className, insn.getField().getFieldName())); if (className != insn.getField().getClassName()) {
insn.setField(referenceCache.getCached(new FieldReference(className, insn.getField().getFieldName())));
} }
@Override
public void visit(ArrayLengthInstruction insn) {
} }
@Override
public void visit(CloneArrayInstruction insn) {
}
@Override
public void visit(GetElementInstruction insn) {
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(UnwrapArrayInstruction insn) {
}
@Override @Override
public void visit(InvokeInstruction insn) { public void visit(InvokeInstruction insn) {
String className = classNameMapper.map(insn.getMethod().getClassName()); String className = classNameMapper.map(insn.getMethod().getClassName());
ValueType[] signature = insn.getMethod().getSignature(); ValueType[] signature = insn.getMethod().getSignature();
boolean changed = true;
for (int i = 0; i < signature.length; ++i) { for (int i = 0; i < signature.length; ++i) {
signature[i] = rename(signature[i]); ValueType type = signature[i];
ValueType newType = rename(type);
if (newType != null) {
changed = true;
}
signature[i] = newType;
}
if (changed) {
insn.setMethod(referenceCache.getCached(new MethodReference(className,
new MethodDescriptor(insn.getMethod().getName(), signature))));
} }
insn.setMethod(new MethodReference(className, new MethodDescriptor(insn.getMethod().getName(), signature)));
} }
@Override @Override
@ -405,16 +300,4 @@ public class ClassRefsRenamer implements InstructionVisitor {
public void visit(InitClassInstruction insn) { public void visit(InitClassInstruction insn) {
insn.setClassName(classNameMapper.map(insn.getClassName())); insn.setClassName(classNameMapper.map(insn.getClassName()));
} }
@Override
public void visit(NullCheckInstruction insn) {
}
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -18,6 +18,7 @@ package org.teavm.parsing;
import java.util.Date; import java.util.Date;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderSource;
import org.teavm.model.ReferenceCache;
import org.teavm.parsing.resource.ClasspathResourceReader; import org.teavm.parsing.resource.ClasspathResourceReader;
import org.teavm.parsing.resource.MapperClassHolderSource; import org.teavm.parsing.resource.MapperClassHolderSource;
import org.teavm.parsing.resource.ResourceClassHolderMapper; import org.teavm.parsing.resource.ResourceClassHolderMapper;
@ -27,9 +28,10 @@ public class ClasspathClassHolderSource implements ClassHolderSource, ClassDateP
private ClasspathResourceMapper classPathMapper; private ClasspathResourceMapper classPathMapper;
public ClasspathClassHolderSource(ClassLoader classLoader) { public ClasspathClassHolderSource(ClassLoader classLoader) {
ReferenceCache referenceCache = new ReferenceCache();
ClasspathResourceReader reader = new ClasspathResourceReader(classLoader); ClasspathResourceReader reader = new ClasspathResourceReader(classLoader);
ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader); ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader, referenceCache);
classPathMapper = new ClasspathResourceMapper(classLoader, rawMapper); classPathMapper = new ClasspathResourceMapper(classLoader, referenceCache, rawMapper);
innerClassSource = new MapperClassHolderSource(classPathMapper); innerClassSource = new MapperClassHolderSource(classPathMapper);
} }

View File

@ -24,6 +24,7 @@ import java.util.*;
import org.teavm.common.CachedMapper; import org.teavm.common.CachedMapper;
import org.teavm.common.Mapper; import org.teavm.common.Mapper;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ReferenceCache;
public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, ClassDateProvider { public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, ClassDateProvider {
private static final String PACKAGE_PREFIX = "packagePrefix."; private static final String PACKAGE_PREFIX = "packagePrefix.";
@ -33,6 +34,7 @@ public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, Cla
private ClassRefsRenamer renamer; private ClassRefsRenamer renamer;
private ClassLoader classLoader; private ClassLoader classLoader;
private Map<String, ModificationDate> modificationDates = new HashMap<>(); private Map<String, ModificationDate> modificationDates = new HashMap<>();
private ReferenceCache referenceCache;
private static class Transformation { private static class Transformation {
String packageName; String packageName;
@ -41,8 +43,10 @@ public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, Cla
String classPrefix = ""; String classPrefix = "";
} }
public ClasspathResourceMapper(ClassLoader classLoader, Mapper<String, ClassHolder> innerMapper) { public ClasspathResourceMapper(ClassLoader classLoader, ReferenceCache referenceCache,
Mapper<String, ClassHolder> innerMapper) {
this.innerMapper = innerMapper; this.innerMapper = innerMapper;
this.referenceCache = referenceCache;
try { try {
Enumeration<URL> resources = classLoader.getResources("META-INF/teavm.properties"); Enumeration<URL> resources = classLoader.getResources("META-INF/teavm.properties");
Map<String, Transformation> transformationMap = new HashMap<>(); Map<String, Transformation> transformationMap = new HashMap<>();
@ -58,16 +62,18 @@ public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, Cla
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Error reading resources", e); throw new RuntimeException("Error reading resources", e);
} }
renamer = new ClassRefsRenamer(new CachedMapper<>(classNameMapper)); renamer = new ClassRefsRenamer(referenceCache, new CachedMapper<>(classNameMapper));
this.classLoader = classLoader; this.classLoader = classLoader;
} }
public ClasspathResourceMapper(Properties properties, Mapper<String, ClassHolder> innerMapper) { public ClasspathResourceMapper(Properties properties, ReferenceCache referenceCache,
Mapper<String, ClassHolder> innerMapper) {
this.innerMapper = innerMapper; this.innerMapper = innerMapper;
this.referenceCache = referenceCache;
Map<String, Transformation> transformationMap = new HashMap<>(); Map<String, Transformation> transformationMap = new HashMap<>();
loadProperties(properties, transformationMap); loadProperties(properties, transformationMap);
transformations.addAll(transformationMap.values()); transformations.addAll(transformationMap.values());
renamer = new ClassRefsRenamer(new CachedMapper<>(classNameMapper)); renamer = new ClassRefsRenamer(referenceCache, new CachedMapper<>(classNameMapper));
} }
private void loadProperties(Properties properties, Map<String, Transformation> cache) { private void loadProperties(Properties properties, Map<String, Transformation> cache) {
@ -121,8 +127,9 @@ public class ClasspathResourceMapper implements Mapper<String, ClassHolder>, Cla
String className = name.substring(index + 1); String className = name.substring(index + 1);
String packageName = name.substring(0, index); String packageName = name.substring(0, index);
if (className.startsWith(transformation.classPrefix)) { if (className.startsWith(transformation.classPrefix)) {
return packageName.substring(transformation.packagePrefix.length()) + "." String newName = packageName.substring(transformation.packagePrefix.length()) + "."
+ className.substring(transformation.classPrefix.length()); + className.substring(transformation.classPrefix.length());
return referenceCache.getCached(newName);
} }
} }
} }

View File

@ -20,6 +20,7 @@ import java.io.File;
import java.util.Properties; import java.util.Properties;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderSource;
import org.teavm.model.ReferenceCache;
import org.teavm.parsing.resource.DirectoryResourceReader; import org.teavm.parsing.resource.DirectoryResourceReader;
import org.teavm.parsing.resource.MapperClassHolderSource; import org.teavm.parsing.resource.MapperClassHolderSource;
import org.teavm.parsing.resource.ResourceClassHolderMapper; import org.teavm.parsing.resource.ResourceClassHolderMapper;
@ -29,9 +30,10 @@ public class DirectoryClasspathClassHolderSource implements ClassHolderSource {
private ClasspathResourceMapper classPathMapper; private ClasspathResourceMapper classPathMapper;
public DirectoryClasspathClassHolderSource(File baseDir, Properties properties) { public DirectoryClasspathClassHolderSource(File baseDir, Properties properties) {
ReferenceCache referenceCache = new ReferenceCache();
DirectoryResourceReader reader = new DirectoryResourceReader(baseDir); DirectoryResourceReader reader = new DirectoryResourceReader(baseDir);
ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader); ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader, referenceCache);
classPathMapper = new ClasspathResourceMapper(properties, rawMapper); classPathMapper = new ClasspathResourceMapper(properties, referenceCache, rawMapper);
innerClassSource = new MapperClassHolderSource(classPathMapper); innerClassSource = new MapperClassHolderSource(classPathMapper);
} }

View File

@ -74,7 +74,7 @@ public class Parser {
node.accept(adapter); node.accept(adapter);
node = nodeWithoutJsr; node = nodeWithoutJsr;
ValueType[] signature = MethodDescriptor.parseSignature(node.desc); ValueType[] signature = MethodDescriptor.parseSignature(node.desc);
MethodHolder method = new MethodHolder(node.name, signature); MethodHolder method = new MethodHolder(referenceCache.getCached(new MethodDescriptor(node.name, signature)));
parseModifiers(node.access, method, DECL_METHOD); parseModifiers(node.access, method, DECL_METHOD);
ProgramParser programParser = new ProgramParser(referenceCache); ProgramParser programParser = new ProgramParser(referenceCache);
@ -229,26 +229,31 @@ public class Parser {
} }
public ClassHolder parseClass(ClassNode node) { public ClassHolder parseClass(ClassNode node) {
ClassHolder cls = new ClassHolder(node.name.replace('/', '.')); ClassHolder cls = new ClassHolder(referenceCache.getCached(node.name.replace('/', '.')));
parseModifiers(node.access, cls, DECL_CLASS); parseModifiers(node.access, cls, DECL_CLASS);
if (node.superName != null) { if (node.superName != null) {
cls.setParent(node.superName.replace('/', '.')); cls.setParent(referenceCache.getCached(node.superName.replace('/', '.')));
} }
if (cls.getName().equals("java.lang.Object")) { if (cls.getName().equals("java.lang.Object")) {
cls.setParent(null); cls.setParent(null);
} }
if (node.interfaces != null) { if (node.interfaces != null) {
for (String iface : node.interfaces) { for (String iface : node.interfaces) {
cls.getInterfaces().add(iface.replace('/', '.')); cls.getInterfaces().add(referenceCache.getCached(iface.replace('/', '.')));
} }
} }
for (Object obj : node.fields) { for (Object obj : node.fields) {
FieldNode fieldNode = (FieldNode) obj; FieldNode fieldNode = (FieldNode) obj;
cls.addField(parseField(fieldNode)); FieldHolder field = parseField(fieldNode);
cls.addField(field);
field.updateReference(referenceCache);
} }
String fullFileName = node.name.substring(0, node.name.lastIndexOf('/') + 1) + node.sourceFile; String fullFileName = referenceCache.getCached(node.name.substring(0, node.name.lastIndexOf('/') + 1)
+ node.sourceFile);
for (MethodNode methodNode : node.methods) { for (MethodNode methodNode : node.methods) {
cls.addMethod(parseMethod(methodNode, fullFileName)); MethodHolder method = parseMethod(methodNode, fullFileName);
cls.addMethod(method);
method.updateReference(referenceCache);
} }
if (node.outerClass != null) { if (node.outerClass != null) {
cls.setOwnerName(node.outerClass.replace('/', '.')); cls.setOwnerName(node.outerClass.replace('/', '.'));
@ -263,8 +268,8 @@ public class Parser {
} }
public FieldHolder parseField(FieldNode node) { public FieldHolder parseField(FieldNode node) {
FieldHolder field = new FieldHolder(node.name); FieldHolder field = new FieldHolder(referenceCache.getCached(node.name));
field.setType(ValueType.parse(node.desc)); field.setType(referenceCache.getCached(ValueType.parse(node.desc)));
field.setInitialValue(node.value); field.setInitialValue(node.value);
parseModifiers(node.access, field, DECL_FIELD); parseModifiers(node.access, field, DECL_FIELD);
parseAnnotations(field.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); parseAnnotations(field.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations);
@ -358,7 +363,7 @@ public class Parser {
continue; continue;
} }
AnnotationHolder annot = new AnnotationHolder(desc); AnnotationHolder annot = new AnnotationHolder(referenceCache.getCached(desc));
parseAnnotationValues(annot, annotNode.values); parseAnnotationValues(annot, annotNode.values);
annotations.add(annot); annotations.add(annot);
} }
@ -379,10 +384,11 @@ public class Parser {
if (value instanceof String[]) { if (value instanceof String[]) {
String[] enumInfo = (String[]) value; String[] enumInfo = (String[]) value;
ValueType.Object object = (ValueType.Object) ValueType.parse(enumInfo[0]); ValueType.Object object = (ValueType.Object) ValueType.parse(enumInfo[0]);
return new AnnotationValue(new FieldReference(object.getClassName(), enumInfo[1])); return new AnnotationValue(referenceCache.getCached(new FieldReference(object.getClassName(),
enumInfo[1])));
} else if (value instanceof Type) { } else if (value instanceof Type) {
Type cls = (Type) value; Type cls = (Type) value;
return new AnnotationValue(ValueType.parse(cls.getDescriptor())); return new AnnotationValue(referenceCache.getCached(ValueType.parse(cls.getDescriptor())));
} else if (value instanceof List<?>) { } else if (value instanceof List<?>) {
List<?> originalList = (List<?>) value; List<?> originalList = (List<?>) value;
List<AnnotationValue> resultList = new ArrayList<>(); List<AnnotationValue> resultList = new ArrayList<>();
@ -392,7 +398,7 @@ public class Parser {
return new AnnotationValue(resultList); return new AnnotationValue(resultList);
} else if (value instanceof AnnotationNode) { } else if (value instanceof AnnotationNode) {
AnnotationNode annotNode = (AnnotationNode) value; AnnotationNode annotNode = (AnnotationNode) value;
ValueType.Object object = (ValueType.Object) ValueType.parse(annotNode.desc); ValueType.Object object = (ValueType.Object) referenceCache.getCached(ValueType.parse(annotNode.desc));
AnnotationHolder annotation = new AnnotationHolder(object.getClassName()); AnnotationHolder annotation = new AnnotationHolder(object.getClassName());
parseAnnotationValues(annotation, annotNode.values); parseAnnotationValues(annotation, annotNode.values);
return new AnnotationValue(annotation); return new AnnotationValue(annotation);

View File

@ -321,7 +321,7 @@ public class ProgramParser {
if (block != null) { if (block != null) {
TryCatchBlock tryCatch = new TryCatchBlock(); TryCatchBlock tryCatch = new TryCatchBlock();
if (tryCatchNode.type != null) { if (tryCatchNode.type != null) {
tryCatch.setExceptionType(tryCatchNode.type.replace('/', '.')); tryCatch.setExceptionType(referenceCache.getCached(tryCatchNode.type.replace('/', '.')));
} }
tryCatch.setHandler(getBasicBlock(labelIndexes.get(tryCatchNode.handler.getLabel()))); tryCatch.setHandler(getBasicBlock(labelIndexes.get(tryCatchNode.handler.getLabel())));
tryCatch.getHandler().setExceptionVariable(program.variableAt(minLocal + method.maxLocals)); tryCatch.getHandler().setExceptionVariable(program.variableAt(minLocal + method.maxLocals));
@ -359,7 +359,7 @@ public class ProgramParser {
Map<Integer, String> debugNames = new HashMap<>(); Map<Integer, String> debugNames = new HashMap<>();
variableDebugNames.put(builtInstructions.get(0), debugNames); variableDebugNames.put(builtInstructions.get(0), debugNames);
for (LocalVariableNode localVar : localVarNodes) { for (LocalVariableNode localVar : localVarNodes) {
debugNames.put(localVar.index + minLocal, localVar.name); debugNames.put(localVar.index + minLocal, referenceCache.getCached(localVar.name));
} }
accumulatedDebugNames.putAll(debugNames); accumulatedDebugNames.putAll(debugNames);
} }
@ -474,7 +474,7 @@ public class ProgramParser {
String cls = type.replace('/', '.'); String cls = type.replace('/', '.');
ConstructInstruction insn = new ConstructInstruction(); ConstructInstruction insn = new ConstructInstruction();
insn.setReceiver(getVariable(pushSingle())); insn.setReceiver(getVariable(pushSingle()));
insn.setType(cls); insn.setType(referenceCache.getCached(cls));
addInstruction(insn); addInstruction(insn);
break; break;
} }
@ -602,7 +602,7 @@ public class ProgramParser {
} else if (value instanceof Type) { } else if (value instanceof Type) {
Type type = (Type) value; Type type = (Type) value;
if (type.getSort() == Type.METHOD) { if (type.getSort() == Type.METHOD) {
return new RuntimeConstant(MethodDescriptor.parseSignature(type.getDescriptor())); return new RuntimeConstant(parseSignature(type.getDescriptor()));
} else { } else {
return new RuntimeConstant(referenceCache.parseValueTypeCached(type.getDescriptor())); return new RuntimeConstant(referenceCache.parseValueTypeCached(type.getDescriptor()));
} }
@ -725,7 +725,7 @@ public class ProgramParser {
pushConstant((Double) cst); pushConstant((Double) cst);
} else if (cst instanceof String) { } else if (cst instanceof String) {
StringConstantInstruction insn = new StringConstantInstruction(); StringConstantInstruction insn = new StringConstantInstruction();
insn.setConstant((String) cst); insn.setConstant(referenceCache.getCached((String) cst));
insn.setReceiver(getVariable(pushSingle())); insn.setReceiver(getVariable(pushSingle()));
addInstruction(insn); addInstruction(insn);
} else if (cst instanceof Type) { } else if (cst instanceof Type) {
@ -1800,40 +1800,45 @@ public class ProgramParser {
} }
}; };
private static MethodHandle parseHandle(Handle handle) { private MethodHandle parseHandle(Handle handle) {
String owner = referenceCache.getCached(handle.getOwner().replace('/', '.'));
String name = referenceCache.getCached(handle.getName());
switch (handle.getTag()) { switch (handle.getTag()) {
case Opcodes.H_GETFIELD: case Opcodes.H_GETFIELD:
return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.fieldGetter(owner, name,
ValueType.parse(handle.getDesc())); referenceCache.getCached(ValueType.parse(handle.getDesc())));
case Opcodes.H_GETSTATIC: case Opcodes.H_GETSTATIC:
return MethodHandle.staticFieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.staticFieldGetter(owner, name,
ValueType.parse(handle.getDesc())); referenceCache.getCached(ValueType.parse(handle.getDesc())));
case Opcodes.H_PUTFIELD: case Opcodes.H_PUTFIELD:
return MethodHandle.fieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.fieldSetter(owner, name,
ValueType.parse(handle.getDesc())); referenceCache.getCached(ValueType.parse(handle.getDesc())));
case Opcodes.H_PUTSTATIC: case Opcodes.H_PUTSTATIC:
return MethodHandle.staticFieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.staticFieldSetter(owner, name,
ValueType.parse(handle.getDesc())); referenceCache.getCached(ValueType.parse(handle.getDesc())));
case Opcodes.H_INVOKEVIRTUAL: case Opcodes.H_INVOKEVIRTUAL:
return MethodHandle.virtualCaller(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.virtualCaller(owner, name, parseSignature(handle.getDesc()));
MethodDescriptor.parseSignature(handle.getDesc()));
case Opcodes.H_INVOKESTATIC: case Opcodes.H_INVOKESTATIC:
return MethodHandle.staticCaller(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.staticCaller(owner, name, parseSignature(handle.getDesc()));
MethodDescriptor.parseSignature(handle.getDesc()));
case Opcodes.H_INVOKESPECIAL: case Opcodes.H_INVOKESPECIAL:
return MethodHandle.specialCaller(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.specialCaller(owner, name, parseSignature(handle.getDesc()));
MethodDescriptor.parseSignature(handle.getDesc()));
case Opcodes.H_NEWINVOKESPECIAL: case Opcodes.H_NEWINVOKESPECIAL:
return MethodHandle.constructorCaller(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.constructorCaller(owner, name, parseSignature(handle.getDesc()));
MethodDescriptor.parseSignature(handle.getDesc()));
case Opcodes.H_INVOKEINTERFACE: case Opcodes.H_INVOKEINTERFACE:
return MethodHandle.interfaceCaller(handle.getOwner().replace('/', '.'), handle.getName(), return MethodHandle.interfaceCaller(owner, name, parseSignature(handle.getDesc()));
MethodDescriptor.parseSignature(handle.getDesc()));
default: default:
throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag()); throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag());
} }
} }
private ValueType[] parseSignature(String desc) {
ValueType[] signature = MethodDescriptor.parseSignature(desc);
for (int i = 0; i < signature.length; ++i) {
signature[i] = referenceCache.getCached(signature[i]);
}
return signature;
}
private static ValueType getPrimitiveTypeField(String fieldName) { private static ValueType getPrimitiveTypeField(String fieldName) {
switch (fieldName) { switch (fieldName) {
case "java/lang/Boolean.TYPE": case "java/lang/Boolean.TYPE":

View File

@ -25,11 +25,12 @@ import org.teavm.model.ReferenceCache;
import org.teavm.parsing.Parser; import org.teavm.parsing.Parser;
public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> { public class ResourceClassHolderMapper implements Mapper<String, ClassHolder> {
private Parser parser = new Parser(new ReferenceCache()); private Parser parser;
private ResourceReader resourceReader; private ResourceReader resourceReader;
public ResourceClassHolderMapper(ResourceReader resourceReader) { public ResourceClassHolderMapper(ResourceReader resourceReader, ReferenceCache referenceCache) {
this.resourceReader = resourceReader; this.resourceReader = resourceReader;
parser = new Parser(referenceCache);
} }
@Override @Override

View File

@ -377,6 +377,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
cacheStatus = new AnnotationAwareCacheStatus(rawCacheStatus, dependencyAnalyzer.getIncrementalDependencies(), cacheStatus = new AnnotationAwareCacheStatus(rawCacheStatus, dependencyAnalyzer.getIncrementalDependencies(),
dependencyAnalyzer.getClassSource()); dependencyAnalyzer.getClassSource());
cacheStatus.addSynthesizedClasses(dependencyAnalyzer::isSynthesizedClass); cacheStatus.addSynthesizedClasses(dependencyAnalyzer::isSynthesizedClass);
dependencyAnalyzer.setInterruptor(null);
// Link // Link
if (wasCancelled()) { if (wasCancelled()) {

View File

@ -18,6 +18,7 @@ package org.teavm.jso.impl;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Function; import java.util.function.Function;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSArray;
import org.teavm.jso.core.JSArrayReader; import org.teavm.jso.core.JSArrayReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -95,7 +96,8 @@ public final class JSMethods {
public static final MethodReference FUNCTION_AS_OBJECT = new MethodReference(JS.class, "functionAsObject", public static final MethodReference FUNCTION_AS_OBJECT = new MethodReference(JS.class, "functionAsObject",
JSObject.class, JSObject.class, JSObject.class); JSObject.class, JSObject.class, JSObject.class);
private static final ValueType JS_OBJECT = ValueType.object(JSObject.class.getName()); public static final ValueType JS_OBJECT = ValueType.object(JSObject.class.getName());
public static final ValueType JS_ARRAY = ValueType.object(JSArray.class.getName());
private static final MethodReference[] INVOKE_METHODS = new MethodReference[13]; private static final MethodReference[] INVOKE_METHODS = new MethodReference[13];
static { static {

View File

@ -20,7 +20,6 @@ import java.util.function.Function;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.jso.JSFunctor; import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSArray;
import org.teavm.jso.core.JSArrayReader; import org.teavm.jso.core.JSArrayReader;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
@ -29,6 +28,7 @@ import org.teavm.model.ElementModifier;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
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.Variable; import org.teavm.model.Variable;
@ -39,6 +39,8 @@ import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.StringConstantInstruction; import org.teavm.model.instructions.StringConstantInstruction;
class JSValueMarshaller { class JSValueMarshaller {
private static final ValueType stringType = ValueType.parse(String.class);
private ReferenceCache referenceCache = new ReferenceCache();
private Diagnostics diagnostics; private Diagnostics diagnostics;
private JSTypeHelper typeHelper; private JSTypeHelper typeHelper;
private ClassReaderSource classSource; private ClassReaderSource classSource;
@ -123,8 +125,8 @@ class JSValueMarshaller {
if (degree <= 1) { if (degree <= 1) {
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type), insn.setMethod(referenceCache.getCached(new MethodReference(JS.class.getName(), "wrap",
getWrapperType(type))); getWrappedType(type), getWrapperType(type))));
insn.getArguments().add(var); insn.getArguments().add(var);
insn.setReceiver(result); insn.setReceiver(result);
insn.setType(InvocationType.SPECIAL); insn.setType(InvocationType.SPECIAL);
@ -152,8 +154,8 @@ class JSValueMarshaller {
} }
insn = new InvokeInstruction(); insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), "map", getWrappedType(type), insn.setMethod(referenceCache.getCached(new MethodReference(JS.class.getName(), "map",
ValueType.parse(Function.class), getWrapperType(type))); getWrappedType(type), ValueType.parse(Function.class), getWrapperType(type))));
insn.getArguments().add(var); insn.getArguments().add(var);
insn.getArguments().add(function); insn.getArguments().add(function);
insn.setReceiver(result); insn.setReceiver(result);
@ -176,7 +178,7 @@ class JSValueMarshaller {
if (type.isObject(String.class)) { if (type.isObject(String.class)) {
return type; return type;
} else { } else {
return ValueType.parse(JSObject.class); return JSMethods.JS_OBJECT;
} }
} else { } else {
return type; return type;
@ -185,9 +187,9 @@ class JSValueMarshaller {
private ValueType getWrapperType(ValueType type) { private ValueType getWrapperType(ValueType type) {
if (type instanceof ValueType.Array) { if (type instanceof ValueType.Array) {
return ValueType.parse(JSArray.class); return JSMethods.JS_ARRAY;
} else { } else {
return ValueType.parse(JSObject.class); return JSMethods.JS_OBJECT;
} }
} }
@ -232,25 +234,25 @@ class JSValueMarshaller {
if (type instanceof ValueType.Primitive) { if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) { switch (((ValueType.Primitive) type).getKind()) {
case BOOLEAN: case BOOLEAN:
return unwrap(var, "unwrapBoolean", ValueType.parse(JSObject.class), ValueType.BOOLEAN, return unwrap(var, "unwrapBoolean", JSMethods.JS_OBJECT, ValueType.BOOLEAN,
location.getSourceLocation()); location.getSourceLocation());
case BYTE: case BYTE:
return unwrap(var, "unwrapByte", ValueType.parse(JSObject.class), ValueType.BYTE, return unwrap(var, "unwrapByte", JSMethods.JS_OBJECT, ValueType.BYTE,
location.getSourceLocation()); location.getSourceLocation());
case SHORT: case SHORT:
return unwrap(var, "unwrapShort", ValueType.parse(JSObject.class), ValueType.SHORT, return unwrap(var, "unwrapShort", JSMethods.JS_OBJECT, ValueType.SHORT,
location.getSourceLocation()); location.getSourceLocation());
case INTEGER: case INTEGER:
return unwrap(var, "unwrapInt", ValueType.parse(JSObject.class), ValueType.INTEGER, return unwrap(var, "unwrapInt", JSMethods.JS_OBJECT, ValueType.INTEGER,
location.getSourceLocation()); location.getSourceLocation());
case CHARACTER: case CHARACTER:
return unwrap(var, "unwrapCharacter", ValueType.parse(JSObject.class), ValueType.CHARACTER, return unwrap(var, "unwrapCharacter", JSMethods.JS_OBJECT, ValueType.CHARACTER,
location.getSourceLocation()); location.getSourceLocation());
case DOUBLE: case DOUBLE:
return unwrap(var, "unwrapDouble", ValueType.parse(JSObject.class), ValueType.DOUBLE, return unwrap(var, "unwrapDouble", JSMethods.JS_OBJECT, ValueType.DOUBLE,
location.getSourceLocation()); location.getSourceLocation());
case FLOAT: case FLOAT:
return unwrap(var, "unwrapFloat", ValueType.parse(JSObject.class), ValueType.FLOAT, return unwrap(var, "unwrapFloat", JSMethods.JS_OBJECT, ValueType.FLOAT,
location.getSourceLocation()); location.getSourceLocation());
case LONG: case LONG:
break; break;
@ -260,8 +262,7 @@ class JSValueMarshaller {
if (className.equals(JSObject.class.getName())) { if (className.equals(JSObject.class.getName())) {
return var; return var;
} else if (className.equals("java.lang.String")) { } else if (className.equals("java.lang.String")) {
return unwrap(var, "unwrapString", ValueType.parse(JSObject.class), ValueType.parse(String.class), return unwrap(var, "unwrapString", JSMethods.JS_OBJECT, stringType, location.getSourceLocation());
location.getSourceLocation());
} else if (typeHelper.isJavaScriptClass(className)) { } else if (typeHelper.isJavaScriptClass(className)) {
Variable result = program.createVariable(); Variable result = program.createVariable();
CastInstruction castInsn = new CastInstruction(); CastInstruction castInsn = new CastInstruction();
@ -451,7 +452,8 @@ class JSValueMarshaller {
} }
Variable result = program.createVariable(); Variable result = program.createVariable();
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setMethod(new MethodReference(JS.class.getName(), methodName, argType, resultType)); insn.setMethod(referenceCache.getCached(referenceCache.getCached(new MethodReference(
JS.class.getName(), methodName, argType, resultType))));
insn.getArguments().add(var); insn.getArguments().add(var);
insn.setReceiver(result); insn.setReceiver(result);
insn.setType(InvocationType.SPECIAL); insn.setType(InvocationType.SPECIAL);
@ -482,7 +484,7 @@ class JSValueMarshaller {
} }
Variable addStringWrap(Variable var, TextLocation location) { Variable addStringWrap(Variable var, TextLocation location) {
return wrap(var, ValueType.object("java.lang.String"), location, false); return wrap(var, stringType, location, false);
} }
Variable addString(String str, TextLocation location) { Variable addString(String str, TextLocation location) {

View File

@ -47,11 +47,21 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
MetaprogrammingImpl.classLoader = proxyClassLoader; MetaprogrammingImpl.classLoader = proxyClassLoader;
MetaprogrammingImpl.classSource = agent.getClassSource(); MetaprogrammingImpl.classSource = agent.getClassSource();
MetaprogrammingImpl.hierarchy = agent.getClassHierarchy(); MetaprogrammingImpl.hierarchy = agent.getClassHierarchy();
MetaprogrammingImpl.incrementaDependencies = agent.getIncrementalCache(); MetaprogrammingImpl.incrementalDependencies = agent.getIncrementalCache();
MetaprogrammingImpl.agent = agent; MetaprogrammingImpl.agent = agent;
MetaprogrammingImpl.reflectContext = new ReflectContext(agent.getClassHierarchy(), proxyClassLoader); MetaprogrammingImpl.reflectContext = new ReflectContext(agent.getClassHierarchy(), proxyClassLoader);
} }
@Override
public void complete() {
MetaprogrammingImpl.classLoader = null;
MetaprogrammingImpl.classSource = null;
MetaprogrammingImpl.hierarchy = null;
MetaprogrammingImpl.incrementalDependencies = null;
MetaprogrammingImpl.agent = null;
MetaprogrammingImpl.reflectContext = null;
}
@Override @Override
public void methodReached(DependencyAgent agent, MethodDependency methodDep) { public void methodReached(DependencyAgent agent, MethodDependency methodDep) {
MethodModel proxy = describer.getMethod(methodDep.getReference()); MethodModel proxy = describer.getMethod(methodDep.getReference());

View File

@ -65,7 +65,7 @@ public final class MetaprogrammingImpl {
static ClassLoader classLoader; static ClassLoader classLoader;
static ClassReaderSource classSource; static ClassReaderSource classSource;
static ClassHierarchy hierarchy; static ClassHierarchy hierarchy;
static IncrementalDependencyRegistration incrementaDependencies; static IncrementalDependencyRegistration incrementalDependencies;
static ReflectContext reflectContext; static ReflectContext reflectContext;
static DependencyAgent agent; static DependencyAgent agent;
static VariableContext varContext; static VariableContext varContext;
@ -320,7 +320,7 @@ public final class MetaprogrammingImpl {
ValueImpl<T> result = new ValueImpl<>(nestedVarContext.createInstance(generator), varContext, innerType); ValueImpl<T> result = new ValueImpl<>(nestedVarContext.createInstance(generator), varContext, innerType);
incrementaDependencies.setNoCache(cls.getName()); incrementalDependencies.setNoCache(cls.getName());
agent.submitClass(cls); agent.submitClass(cls);
return result; return result;
} }

View File

@ -23,6 +23,19 @@ import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap; import org.teavm.platform.metadata.ResourceMap;
class ResourceProgramTransformer { class ResourceProgramTransformer {
private static final MethodReference CAST_TO_STRING = new MethodReference(ResourceAccessor.class, "castToString",
Object.class, String.class);
private static final MethodReference CAST_FROM_STRING = new MethodReference(ResourceAccessor.class,
"castFromString", String.class, Object.class);
private static final MethodReference PUT = new MethodReference(ResourceAccessor.class, "put",
Object.class, String.class, Object.class, void.class);
private static final MethodReference KEYS = new MethodReference(ResourceAccessor.class, "keys",
Object.class, Object.class);
private static final MethodReference KEYS_TO_STRINGS = new MethodReference(ResourceAccessor.class, "keysToStrings",
Object.class, String[].class);
private static final MethodReference GET_PROPERTY = new MethodReference(ResourceAccessor.class, "getProperty",
Object.class, String.class, Object.class);
private ClassHierarchy hierarchy; private ClassHierarchy hierarchy;
private Program program; private Program program;
@ -97,14 +110,13 @@ class ResourceProgramTransformer {
InvokeInstruction keysInsn = new InvokeInstruction(); InvokeInstruction keysInsn = new InvokeInstruction();
keysInsn.setType(InvocationType.SPECIAL); keysInsn.setType(InvocationType.SPECIAL);
keysInsn.setMethod(new MethodReference(ResourceAccessor.class, "keys", Object.class, Object.class)); keysInsn.setMethod(KEYS);
keysInsn.getArguments().add(insn.getInstance()); keysInsn.getArguments().add(insn.getInstance());
keysInsn.setReceiver(tmp); keysInsn.setReceiver(tmp);
InvokeInstruction transformInsn = new InvokeInstruction(); InvokeInstruction transformInsn = new InvokeInstruction();
transformInsn.setType(InvocationType.SPECIAL); transformInsn.setType(InvocationType.SPECIAL);
transformInsn.setMethod(new MethodReference(ResourceAccessor.class, "keysToStrings", transformInsn.setMethod(KEYS_TO_STRINGS);
Object.class, String[].class));
transformInsn.getArguments().add(tmp); transformInsn.getArguments().add(tmp);
transformInsn.setReceiver(insn.getReceiver()); transformInsn.setReceiver(insn.getReceiver());
@ -148,8 +160,7 @@ class ResourceProgramTransformer {
getProperty(insn, property, instructions, resultVar); getProperty(insn, property, instructions, resultVar);
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString", castInvoke.setMethod(CAST_TO_STRING);
Object.class, String.class));
castInvoke.getArguments().add(resultVar); castInvoke.getArguments().add(resultVar);
castInvoke.setReceiver(insn.getReceiver()); castInvoke.setReceiver(insn.getReceiver());
instructions.add(castInvoke); instructions.add(castInvoke);
@ -179,8 +190,7 @@ class ResourceProgramTransformer {
instructions.add(nameInsn); instructions.add(nameInsn);
InvokeInstruction accessorInvoke = new InvokeInstruction(); InvokeInstruction accessorInvoke = new InvokeInstruction();
accessorInvoke.setType(InvocationType.SPECIAL); accessorInvoke.setType(InvocationType.SPECIAL);
accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "getProperty", accessorInvoke.setMethod(GET_PROPERTY);
Object.class, String.class, Object.class));
accessorInvoke.getArguments().add(insn.getInstance()); accessorInvoke.getArguments().add(insn.getInstance());
accessorInvoke.getArguments().add(nameVar); accessorInvoke.getArguments().add(nameVar);
accessorInvoke.setReceiver(resultVar); accessorInvoke.setReceiver(resultVar);
@ -236,8 +246,7 @@ class ResourceProgramTransformer {
Variable castVar = insn.getProgram().createVariable(); Variable castVar = insn.getProgram().createVariable();
InvokeInstruction castInvoke = new InvokeInstruction(); InvokeInstruction castInvoke = new InvokeInstruction();
castInvoke.setType(InvocationType.SPECIAL); castInvoke.setType(InvocationType.SPECIAL);
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString", castInvoke.setMethod(CAST_FROM_STRING);
String.class, Object.class));
castInvoke.getArguments().add(insn.getArguments().get(0)); castInvoke.getArguments().add(insn.getArguments().get(0));
castInvoke.setReceiver(castVar); castInvoke.setReceiver(castVar);
instructions.add(castInvoke); instructions.add(castInvoke);
@ -262,8 +271,7 @@ class ResourceProgramTransformer {
instructions.add(nameInsn); instructions.add(nameInsn);
InvokeInstruction accessorInvoke = new InvokeInstruction(); InvokeInstruction accessorInvoke = new InvokeInstruction();
accessorInvoke.setType(InvocationType.SPECIAL); accessorInvoke.setType(InvocationType.SPECIAL);
accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "put", accessorInvoke.setMethod(PUT);
Object.class, String.class, Object.class, void.class));
accessorInvoke.getArguments().add(insn.getInstance()); accessorInvoke.getArguments().add(insn.getInstance());
accessorInvoke.getArguments().add(nameVar); accessorInvoke.getArguments().add(nameVar);
accessorInvoke.getArguments().add(valueVar); accessorInvoke.getArguments().add(valueVar);