From f589b0035a7258af8fe8b80326095e2d12120fff Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 29 Dec 2018 19:02:03 +0300 Subject: [PATCH] Decrease memory consumption --- .../org/teavm/classlib/impl/JCLPlugin.java | 2 +- ...va => StringConcatFactorySubstitutor.java} | 7 +- .../main/java/org/teavm/cache/ProgramIO.java | 2 +- .../AbstractDependencyListener.java | 4 + .../org/teavm/dependency/DependencyAgent.java | 4 + .../teavm/dependency/DependencyAnalyzer.java | 8 +- .../dependency/DependencyClassSource.java | 4 + .../teavm/dependency/DependencyListener.java | 2 + .../org/teavm/model/AnnotationContainer.java | 14 +- .../main/java/org/teavm/model/BasicBlock.java | 96 +++++++++-- .../java/org/teavm/model/FieldHolder.java | 14 +- .../java/org/teavm/model/MethodHolder.java | 7 + core/src/main/java/org/teavm/model/Phi.java | 2 +- .../main/java/org/teavm/model/Program.java | 2 +- .../java/org/teavm/model/ReferenceCache.java | 10 +- .../model/instructions/InvokeInstruction.java | 2 +- .../org/teavm/parsing/ClassRefsRenamer.java | 163 +++--------------- .../parsing/ClasspathClassHolderSource.java | 6 +- .../parsing/ClasspathResourceMapper.java | 17 +- .../DirectoryClasspathClassHolderSource.java | 6 +- .../main/java/org/teavm/parsing/Parser.java | 32 ++-- .../java/org/teavm/parsing/ProgramParser.java | 53 +++--- .../resource/ResourceClassHolderMapper.java | 5 +- core/src/main/java/org/teavm/vm/TeaVM.java | 1 + .../java/org/teavm/jso/impl/JSMethods.java | 4 +- .../org/teavm/jso/impl/JSValueMarshaller.java | 40 +++-- .../MetaprogrammingDependencyListener.java | 12 +- .../impl/MetaprogrammingImpl.java | 4 +- .../plugin/ResourceProgramTransformer.java | 30 ++-- 29 files changed, 298 insertions(+), 255 deletions(-) rename classlib/src/main/java/org/teavm/classlib/impl/{StringConcatFactorySubstritutor.java => StringConcatFactorySubstitutor.java} (93%) diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index b75b0a3fc..99782607c 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -70,7 +70,7 @@ public class JCLPlugin implements TeaVMPlugin { ValueType.arrayOf(ValueType.object("java.lang.Object")), ValueType.object("java.lang.invoke.CallSite")), lms); - StringConcatFactorySubstritutor stringConcatSubstitutor = new StringConcatFactorySubstritutor(); + StringConcatFactorySubstitutor stringConcatSubstitutor = new StringConcatFactorySubstitutor(); 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.MethodType"), ValueType.object("java.lang.invoke.CallSite")), diff --git a/classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstritutor.java b/classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstitutor.java similarity index 93% rename from classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstritutor.java rename to classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstitutor.java index 6bdf37bb9..f79929ede 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstritutor.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/StringConcatFactorySubstitutor.java @@ -18,12 +18,14 @@ package org.teavm.classlib.impl; import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.DynamicCallSite; import org.teavm.model.MethodReference; +import org.teavm.model.ReferenceCache; import org.teavm.model.RuntimeConstant; import org.teavm.model.ValueType; import org.teavm.model.emit.ProgramEmitter; 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 char VALUE_ARGUMENT = '\1'; private static final char CONST_ARGUMENT = '\2'; @@ -100,7 +102,8 @@ public class StringConcatFactorySubstritutor implements BootstrapMethodSubstitut if (!(type instanceof ValueType.Primitive)) { 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); } diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index 25a8ab3f6..eaae23f2e 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -162,7 +162,7 @@ public class ProgramIO { for (int i = 0; i < varCount; ++i) { Variable var = program.createVariable(); var.setRegister(data.readShort()); - var.setDebugName(data.readUTF()); + var.setDebugName(referenceCache.getCached(data.readUTF())); if (var.getDebugName().isEmpty()) { var.setDebugName(null); } diff --git a/core/src/main/java/org/teavm/dependency/AbstractDependencyListener.java b/core/src/main/java/org/teavm/dependency/AbstractDependencyListener.java index f9e6b99a0..5ba0d069d 100644 --- a/core/src/main/java/org/teavm/dependency/AbstractDependencyListener.java +++ b/core/src/main/java/org/teavm/dependency/AbstractDependencyListener.java @@ -35,4 +35,8 @@ public abstract class AbstractDependencyListener implements DependencyListener { @Override public void completing(DependencyAgent agent) { } + + @Override + public void complete() { + } } diff --git a/core/src/main/java/org/teavm/dependency/DependencyAgent.java b/core/src/main/java/org/teavm/dependency/DependencyAgent.java index 4d844537d..4c36eabbd 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyAgent.java +++ b/core/src/main/java/org/teavm/dependency/DependencyAgent.java @@ -135,4 +135,8 @@ public class DependencyAgent implements DependencyInfo, ServiceRepository { public IncrementalDependencyRegistration getIncrementalCache() { return analyzer.incrementalCache; } + + void cleanup() { + analyzer = null; + } } diff --git a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java index ff9ae1abe..f322f87cb 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java +++ b/core/src/main/java/org/teavm/dependency/DependencyAnalyzer.java @@ -700,6 +700,10 @@ public abstract class DependencyAnalyzer implements DependencyInfo { } } + for (DependencyListener listener : listeners) { + listener.complete(); + } + if (dependencyReport) { reportDependencies(); } @@ -745,6 +749,8 @@ public abstract class DependencyAnalyzer implements DependencyInfo { } allNodes.clear(); + classSource.cleanup(); + agent.cleanup(); } static class ReportEntry { @@ -903,7 +909,7 @@ public abstract class DependencyAnalyzer implements DependencyInfo { splitter.fixProgram(); } - class IncrementalCache implements IncrementalDependencyProvider, IncrementalDependencyRegistration { + static class IncrementalCache implements IncrementalDependencyProvider, IncrementalDependencyRegistration { private final String[] emptyArray = new String[0]; private Map classes = new HashMap<>(); private Map methods = new HashMap<>(); diff --git a/core/src/main/java/org/teavm/dependency/DependencyClassSource.java b/core/src/main/java/org/teavm/dependency/DependencyClassSource.java index 1dbd9f22c..22adae04e 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyClassSource.java +++ b/core/src/main/java/org/teavm/dependency/DependencyClassSource.java @@ -105,6 +105,10 @@ class DependencyClassSource implements ClassHolderSource { transformers.add(transformer); } + public void cleanup() { + transformers.clear(); + } + final ClassHolderTransformerContext transformContext = new ClassHolderTransformerContext() { @Override public ClassHierarchy getHierarchy() { diff --git a/core/src/main/java/org/teavm/dependency/DependencyListener.java b/core/src/main/java/org/teavm/dependency/DependencyListener.java index 99b206eda..658b11db5 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyListener.java +++ b/core/src/main/java/org/teavm/dependency/DependencyListener.java @@ -25,4 +25,6 @@ public interface DependencyListener { void fieldReached(DependencyAgent agent, FieldDependency field); void completing(DependencyAgent agent); + + void complete(); } diff --git a/core/src/main/java/org/teavm/model/AnnotationContainer.java b/core/src/main/java/org/teavm/model/AnnotationContainer.java index d8a296cc3..94ef5727e 100644 --- a/core/src/main/java/org/teavm/model/AnnotationContainer.java +++ b/core/src/main/java/org/teavm/model/AnnotationContainer.java @@ -15,13 +15,17 @@ */ package org.teavm.model; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; public class AnnotationContainer implements AnnotationContainerReader { - private Map annotations = new LinkedHashMap<>(); + private Map annotations; public void add(AnnotationHolder annotation) { + if (annotations == null) { + annotations = new LinkedHashMap<>(); + } if (annotations.containsKey(annotation.getType())) { throw new IllegalArgumentException("Annotation of type " + annotation.getType() + " is already there"); } @@ -30,7 +34,7 @@ public class AnnotationContainer implements AnnotationContainerReader { @Override public AnnotationHolder get(String type) { - return annotations.get(type); + return annotations != null ? annotations.get(type) : null; } public void remove(AnnotationHolder annotation) { @@ -42,11 +46,13 @@ public class AnnotationContainer implements AnnotationContainerReader { } public void remove(String type) { - annotations.remove(type); + if (annotations != null) { + annotations.remove(type); + } } @Override public Iterable all() { - return annotations.values(); + return annotations != null ? annotations.values() : Collections.emptyList(); } } diff --git a/core/src/main/java/org/teavm/model/BasicBlock.java b/core/src/main/java/org/teavm/model/BasicBlock.java index 67dfa5fc7..f570d93bc 100644 --- a/core/src/main/java/org/teavm/model/BasicBlock.java +++ b/core/src/main/java/org/teavm/model/BasicBlock.java @@ -17,7 +17,6 @@ package org.teavm.model; import java.util.AbstractList; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -28,8 +27,8 @@ import org.teavm.model.util.TransitionExtractor; public class BasicBlock implements BasicBlockReader, Iterable { private Program program; private int index; - private List phis = new ArrayList<>(); - private List tryCatchBlocks = new ArrayList<>(); + private List phis; + private List tryCatchBlocks; private Variable exceptionVariable; private String label; Instruction firstInstruction; @@ -172,12 +171,15 @@ public class BasicBlock implements BasicBlockReader, Iterable { private List safePhis = new AbstractList() { @Override public Phi get(int index) { + if (phis == null) { + throw new IndexOutOfBoundsException(); + } return phis.get(index); } @Override public int size() { - return phis.size(); + return phis != null ? phis.size() : 0; } @Override @@ -186,6 +188,9 @@ public class BasicBlock implements BasicBlockReader, Iterable { throw new IllegalArgumentException("This phi is already in some basic block"); } e.setBasicBlock(BasicBlock.this); + if (phis == null) { + phis = new ArrayList<>(1); + } phis.add(index, e); } @@ -194,6 +199,9 @@ public class BasicBlock implements BasicBlockReader, Iterable { if (element.getBasicBlock() != null) { throw new IllegalArgumentException("This phi is already in some basic block"); } + if (phis == null) { + phis = new ArrayList<>(1); + } Phi oldPhi = phis.get(index); oldPhi.setBasicBlock(null); element.setBasicBlock(BasicBlock.this); @@ -202,6 +210,9 @@ public class BasicBlock implements BasicBlockReader, Iterable { @Override public Phi remove(int index) { + if (phis == null) { + throw new IndexOutOfBoundsException(); + } Phi phi = phis.remove(index); phi.setBasicBlock(null); return phi; @@ -209,10 +220,13 @@ public class BasicBlock implements BasicBlockReader, Iterable { @Override public void clear() { + if (phis == null) { + return; + } for (Phi phi : phis) { phi.setBasicBlock(null); } - phis.clear(); + phis = null; } }; @@ -220,7 +234,20 @@ public class BasicBlock implements BasicBlockReader, Iterable { return safePhis; } - private List immutablePhis = Collections.unmodifiableList(phis); + private List immutablePhis = new AbstractList() { + @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 public List readPhis() { @@ -299,7 +326,20 @@ public class BasicBlock implements BasicBlockReader, Iterable { } } - private List immutableTryCatchBlocks = Collections.unmodifiableList(tryCatchBlocks); + private List immutableTryCatchBlocks = new AbstractList() { + @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 public List readTryCatchBlocks() { @@ -307,25 +347,43 @@ public class BasicBlock implements BasicBlockReader, Iterable { } private List safeTryCatchBlocks = new AbstractList() { - @Override public TryCatchBlock get(int index) { + @Override + public TryCatchBlock get(int index) { + if (tryCatchBlocks == null) { + throw new IndexOutOfBoundsException(); + } 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) { throw new IllegalStateException("This try/catch block is already added to basic block"); } element.protectedBlock = BasicBlock.this; + if (tryCatchBlocks == null) { + tryCatchBlocks = new ArrayList<>(1); + } 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); tryCatch.protectedBlock = null; return tryCatch; } - @Override public TryCatchBlock set(int index, TryCatchBlock element) { + + @Override + public TryCatchBlock set(int index, TryCatchBlock element) { TryCatchBlock oldTryCatch = tryCatchBlocks.get(index); if (oldTryCatch == element) { return oldTryCatch; @@ -335,14 +393,22 @@ public class BasicBlock implements BasicBlockReader, Iterable { } oldTryCatch.protectedBlock = null; element.protectedBlock = BasicBlock.this; + if (tryCatchBlocks == null) { + tryCatchBlocks = new ArrayList<>(1); + } tryCatchBlocks.set(index, element); return oldTryCatch; } - @Override public void clear() { + + @Override + public void clear() { + if (tryCatchBlocks == null) { + return; + } for (TryCatchBlock tryCatch : tryCatchBlocks) { tryCatch.protectedBlock = null; } - tryCatchBlocks.clear(); + tryCatchBlocks = null; } }; diff --git a/core/src/main/java/org/teavm/model/FieldHolder.java b/core/src/main/java/org/teavm/model/FieldHolder.java index 48b87b419..9398def4f 100644 --- a/core/src/main/java/org/teavm/model/FieldHolder.java +++ b/core/src/main/java/org/teavm/model/FieldHolder.java @@ -19,6 +19,7 @@ public class FieldHolder extends MemberHolder implements FieldReader { private ValueType type; private Object initialValue; private ClassHolder owner; + private FieldReference reference; public FieldHolder(String name) { super(name); @@ -48,6 +49,7 @@ public class FieldHolder extends MemberHolder implements FieldReader { void setOwner(ClassHolder owner) { this.owner = owner; + reference = null; } @Override @@ -57,6 +59,16 @@ public class FieldHolder extends MemberHolder implements FieldReader { @Override 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); + } } } diff --git a/core/src/main/java/org/teavm/model/MethodHolder.java b/core/src/main/java/org/teavm/model/MethodHolder.java index ccc624541..151d448a4 100644 --- a/core/src/main/java/org/teavm/model/MethodHolder.java +++ b/core/src/main/java/org/teavm/model/MethodHolder.java @@ -101,6 +101,13 @@ public class MethodHolder extends MemberHolder implements MethodReader { return reference; } + public void updateReference(ReferenceCache cache) { + MethodReference reference = getReference(); + if (reference != null) { + this.reference = cache.getCached(reference); + } + } + @Override public Program getProgram() { return program; diff --git a/core/src/main/java/org/teavm/model/Phi.java b/core/src/main/java/org/teavm/model/Phi.java index 40db6ddaf..99bb8d7d5 100644 --- a/core/src/main/java/org/teavm/model/Phi.java +++ b/core/src/main/java/org/teavm/model/Phi.java @@ -23,7 +23,7 @@ import java.util.List; public class Phi implements PhiReader { private BasicBlock basicBlock; private Variable receiver; - private List incomings = new ArrayList<>(); + private List incomings = new ArrayList<>(2); @Override public BasicBlock getBasicBlock() { diff --git a/core/src/main/java/org/teavm/model/Program.java b/core/src/main/java/org/teavm/model/Program.java index c35e01b9a..a9cf43833 100644 --- a/core/src/main/java/org/teavm/model/Program.java +++ b/core/src/main/java/org/teavm/model/Program.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.List; public class Program implements ProgramReader { - private List basicBlocks = new ArrayList<>(); + private List basicBlocks = new ArrayList<>(2); private List variables = new ArrayList<>(); private MethodHolder method; private boolean packed; diff --git a/core/src/main/java/org/teavm/model/ReferenceCache.java b/core/src/main/java/org/teavm/model/ReferenceCache.java index 5295e2631..939bcc487 100644 --- a/core/src/main/java/org/teavm/model/ReferenceCache.java +++ b/core/src/main/java/org/teavm/model/ReferenceCache.java @@ -23,7 +23,7 @@ public class ReferenceCache { private Map fieldRefenceCache = new HashMap<>(); private Map descriptorCache = new HashMap<>(); private Map valueTypeCache = new HashMap<>(); - private Map classCache = new HashMap<>(); + private Map stringCache = new HashMap<>(); private Map referenceParseCache = new HashMap<>(); private Map descriptorParseCache = new HashMap<>(); private Map valueTypeParseCache = new HashMap<>(); @@ -103,11 +103,11 @@ public class ReferenceCache { return result; } - public String getCached(String className) { - String result = classCache.get(className); + public String getCached(String s) { + String result = stringCache.get(s); if (result == null) { - result = className; - classCache.put(result, result); + result = s; + stringCache.put(result, result); } return result; } diff --git a/core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java b/core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java index c9cadea23..213349458 100644 --- a/core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java @@ -25,7 +25,7 @@ public class InvokeInstruction extends Instruction { private InvocationType type; private MethodReference method; private Variable instance; - private List arguments = new ArrayList<>(); + private List arguments = new ArrayList<>(1); private Variable receiver; public InvocationType getType() { diff --git a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index c78a8203e..5c0a34dec 100644 --- a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -35,51 +35,28 @@ import org.teavm.model.MethodHandle; import org.teavm.model.MethodHolder; import org.teavm.model.MethodReference; import org.teavm.model.Program; +import org.teavm.model.ReferenceCache; import org.teavm.model.RuntimeConstant; import org.teavm.model.TryCatchBlock; import org.teavm.model.ValueType; -import org.teavm.model.instructions.ArrayLengthInstruction; -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.AbstractInstructionVisitor; 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.CloneArrayInstruction; import org.teavm.model.instructions.ConstructArrayInstruction; import org.teavm.model.instructions.ConstructInstruction; 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.InitClassInstruction; -import org.teavm.model.instructions.InstructionVisitor; -import org.teavm.model.instructions.IntegerConstantInstruction; import org.teavm.model.instructions.InvokeInstruction; 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.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 classNameMapper; - public ClassRefsRenamer(Mapper classNameMapper) { + public ClassRefsRenamer(ReferenceCache referenceCache, Mapper classNameMapper) { + this.referenceCache = referenceCache; this.classNameMapper = classNameMapper; } @@ -153,10 +130,10 @@ public class ClassRefsRenamer implements InstructionVisitor { private ValueType rename(ValueType type) { if (type instanceof ValueType.Array) { ValueType itemType = ((ValueType.Array) type).getItemType(); - return ValueType.arrayOf(rename(itemType)); + return referenceCache.getCached(ValueType.arrayOf(rename(itemType))); } else if (type instanceof ValueType.Object) { String className = ((ValueType.Object) type).getClassName(); - return ValueType.object(classNameMapper.map(className)); + return referenceCache.getCached(ValueType.object(classNameMapper.map(className))); } else { return type; } @@ -245,88 +222,16 @@ public class ClassRefsRenamer implements InstructionVisitor { } } - @Override - public void visit(EmptyInstruction insn) { - } - @Override public void visit(ClassConstantInstruction insn) { 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 public void visit(CastInstruction insn) { 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 public void visit(ConstructArrayInstruction insn) { insn.setItemType(rename(insn.getItemType())); @@ -345,43 +250,33 @@ public class ClassRefsRenamer implements InstructionVisitor { @Override public void visit(GetFieldInstruction insn) { 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 public void visit(PutFieldInstruction insn) { 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 public void visit(InvokeInstruction insn) { String className = classNameMapper.map(insn.getMethod().getClassName()); ValueType[] signature = insn.getMethod().getSignature(); + boolean changed = true; 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 @@ -405,16 +300,4 @@ public class ClassRefsRenamer implements InstructionVisitor { public void visit(InitClassInstruction insn) { insn.setClassName(classNameMapper.map(insn.getClassName())); } - - @Override - public void visit(NullCheckInstruction insn) { - } - - @Override - public void visit(MonitorEnterInstruction insn) { - } - - @Override - public void visit(MonitorExitInstruction insn) { - } } diff --git a/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java b/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java index b167fdb91..0b3cd90c6 100644 --- a/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java +++ b/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java @@ -18,6 +18,7 @@ package org.teavm.parsing; import java.util.Date; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; +import org.teavm.model.ReferenceCache; import org.teavm.parsing.resource.ClasspathResourceReader; import org.teavm.parsing.resource.MapperClassHolderSource; import org.teavm.parsing.resource.ResourceClassHolderMapper; @@ -27,9 +28,10 @@ public class ClasspathClassHolderSource implements ClassHolderSource, ClassDateP private ClasspathResourceMapper classPathMapper; public ClasspathClassHolderSource(ClassLoader classLoader) { + ReferenceCache referenceCache = new ReferenceCache(); ClasspathResourceReader reader = new ClasspathResourceReader(classLoader); - ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader); - classPathMapper = new ClasspathResourceMapper(classLoader, rawMapper); + ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader, referenceCache); + classPathMapper = new ClasspathResourceMapper(classLoader, referenceCache, rawMapper); innerClassSource = new MapperClassHolderSource(classPathMapper); } diff --git a/core/src/main/java/org/teavm/parsing/ClasspathResourceMapper.java b/core/src/main/java/org/teavm/parsing/ClasspathResourceMapper.java index 3b5955a30..7d3c8f349 100644 --- a/core/src/main/java/org/teavm/parsing/ClasspathResourceMapper.java +++ b/core/src/main/java/org/teavm/parsing/ClasspathResourceMapper.java @@ -24,6 +24,7 @@ import java.util.*; import org.teavm.common.CachedMapper; import org.teavm.common.Mapper; import org.teavm.model.ClassHolder; +import org.teavm.model.ReferenceCache; public class ClasspathResourceMapper implements Mapper, ClassDateProvider { private static final String PACKAGE_PREFIX = "packagePrefix."; @@ -33,6 +34,7 @@ public class ClasspathResourceMapper implements Mapper, Cla private ClassRefsRenamer renamer; private ClassLoader classLoader; private Map modificationDates = new HashMap<>(); + private ReferenceCache referenceCache; private static class Transformation { String packageName; @@ -41,8 +43,10 @@ public class ClasspathResourceMapper implements Mapper, Cla String classPrefix = ""; } - public ClasspathResourceMapper(ClassLoader classLoader, Mapper innerMapper) { + public ClasspathResourceMapper(ClassLoader classLoader, ReferenceCache referenceCache, + Mapper innerMapper) { this.innerMapper = innerMapper; + this.referenceCache = referenceCache; try { Enumeration resources = classLoader.getResources("META-INF/teavm.properties"); Map transformationMap = new HashMap<>(); @@ -58,16 +62,18 @@ public class ClasspathResourceMapper implements Mapper, Cla } catch (IOException e) { throw new RuntimeException("Error reading resources", e); } - renamer = new ClassRefsRenamer(new CachedMapper<>(classNameMapper)); + renamer = new ClassRefsRenamer(referenceCache, new CachedMapper<>(classNameMapper)); this.classLoader = classLoader; } - public ClasspathResourceMapper(Properties properties, Mapper innerMapper) { + public ClasspathResourceMapper(Properties properties, ReferenceCache referenceCache, + Mapper innerMapper) { this.innerMapper = innerMapper; + this.referenceCache = referenceCache; Map transformationMap = new HashMap<>(); loadProperties(properties, transformationMap); transformations.addAll(transformationMap.values()); - renamer = new ClassRefsRenamer(new CachedMapper<>(classNameMapper)); + renamer = new ClassRefsRenamer(referenceCache, new CachedMapper<>(classNameMapper)); } private void loadProperties(Properties properties, Map cache) { @@ -121,8 +127,9 @@ public class ClasspathResourceMapper implements Mapper, Cla String className = name.substring(index + 1); String packageName = name.substring(0, index); if (className.startsWith(transformation.classPrefix)) { - return packageName.substring(transformation.packagePrefix.length()) + "." + String newName = packageName.substring(transformation.packagePrefix.length()) + "." + className.substring(transformation.classPrefix.length()); + return referenceCache.getCached(newName); } } } diff --git a/core/src/main/java/org/teavm/parsing/DirectoryClasspathClassHolderSource.java b/core/src/main/java/org/teavm/parsing/DirectoryClasspathClassHolderSource.java index 7663a7bec..3848e71ea 100644 --- a/core/src/main/java/org/teavm/parsing/DirectoryClasspathClassHolderSource.java +++ b/core/src/main/java/org/teavm/parsing/DirectoryClasspathClassHolderSource.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.Properties; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; +import org.teavm.model.ReferenceCache; import org.teavm.parsing.resource.DirectoryResourceReader; import org.teavm.parsing.resource.MapperClassHolderSource; import org.teavm.parsing.resource.ResourceClassHolderMapper; @@ -29,9 +30,10 @@ public class DirectoryClasspathClassHolderSource implements ClassHolderSource { private ClasspathResourceMapper classPathMapper; public DirectoryClasspathClassHolderSource(File baseDir, Properties properties) { + ReferenceCache referenceCache = new ReferenceCache(); DirectoryResourceReader reader = new DirectoryResourceReader(baseDir); - ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader); - classPathMapper = new ClasspathResourceMapper(properties, rawMapper); + ResourceClassHolderMapper rawMapper = new ResourceClassHolderMapper(reader, referenceCache); + classPathMapper = new ClasspathResourceMapper(properties, referenceCache, rawMapper); innerClassSource = new MapperClassHolderSource(classPathMapper); } diff --git a/core/src/main/java/org/teavm/parsing/Parser.java b/core/src/main/java/org/teavm/parsing/Parser.java index 9ec7d1052..2c381d1ff 100644 --- a/core/src/main/java/org/teavm/parsing/Parser.java +++ b/core/src/main/java/org/teavm/parsing/Parser.java @@ -74,7 +74,7 @@ public class Parser { node.accept(adapter); node = nodeWithoutJsr; 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); ProgramParser programParser = new ProgramParser(referenceCache); @@ -229,26 +229,31 @@ public class Parser { } 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); if (node.superName != null) { - cls.setParent(node.superName.replace('/', '.')); + cls.setParent(referenceCache.getCached(node.superName.replace('/', '.'))); } if (cls.getName().equals("java.lang.Object")) { cls.setParent(null); } if (node.interfaces != null) { for (String iface : node.interfaces) { - cls.getInterfaces().add(iface.replace('/', '.')); + cls.getInterfaces().add(referenceCache.getCached(iface.replace('/', '.'))); } } for (Object obj : node.fields) { 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) { - cls.addMethod(parseMethod(methodNode, fullFileName)); + MethodHolder method = parseMethod(methodNode, fullFileName); + cls.addMethod(method); + method.updateReference(referenceCache); } if (node.outerClass != null) { cls.setOwnerName(node.outerClass.replace('/', '.')); @@ -263,8 +268,8 @@ public class Parser { } public FieldHolder parseField(FieldNode node) { - FieldHolder field = new FieldHolder(node.name); - field.setType(ValueType.parse(node.desc)); + FieldHolder field = new FieldHolder(referenceCache.getCached(node.name)); + field.setType(referenceCache.getCached(ValueType.parse(node.desc))); field.setInitialValue(node.value); parseModifiers(node.access, field, DECL_FIELD); parseAnnotations(field.getAnnotations(), node.visibleAnnotations, node.invisibleAnnotations); @@ -358,7 +363,7 @@ public class Parser { continue; } - AnnotationHolder annot = new AnnotationHolder(desc); + AnnotationHolder annot = new AnnotationHolder(referenceCache.getCached(desc)); parseAnnotationValues(annot, annotNode.values); annotations.add(annot); } @@ -379,10 +384,11 @@ public class Parser { if (value instanceof String[]) { String[] enumInfo = (String[]) value; 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) { 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) { List originalList = (List) value; List resultList = new ArrayList<>(); @@ -392,7 +398,7 @@ public class Parser { return new AnnotationValue(resultList); } else if (value instanceof AnnotationNode) { 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()); parseAnnotationValues(annotation, annotNode.values); return new AnnotationValue(annotation); diff --git a/core/src/main/java/org/teavm/parsing/ProgramParser.java b/core/src/main/java/org/teavm/parsing/ProgramParser.java index c8f73bcad..27066d515 100644 --- a/core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -321,7 +321,7 @@ public class ProgramParser { if (block != null) { TryCatchBlock tryCatch = new TryCatchBlock(); 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.getHandler().setExceptionVariable(program.variableAt(minLocal + method.maxLocals)); @@ -359,7 +359,7 @@ public class ProgramParser { Map debugNames = new HashMap<>(); variableDebugNames.put(builtInstructions.get(0), debugNames); for (LocalVariableNode localVar : localVarNodes) { - debugNames.put(localVar.index + minLocal, localVar.name); + debugNames.put(localVar.index + minLocal, referenceCache.getCached(localVar.name)); } accumulatedDebugNames.putAll(debugNames); } @@ -474,7 +474,7 @@ public class ProgramParser { String cls = type.replace('/', '.'); ConstructInstruction insn = new ConstructInstruction(); insn.setReceiver(getVariable(pushSingle())); - insn.setType(cls); + insn.setType(referenceCache.getCached(cls)); addInstruction(insn); break; } @@ -602,7 +602,7 @@ public class ProgramParser { } else if (value instanceof Type) { Type type = (Type) value; if (type.getSort() == Type.METHOD) { - return new RuntimeConstant(MethodDescriptor.parseSignature(type.getDescriptor())); + return new RuntimeConstant(parseSignature(type.getDescriptor())); } else { return new RuntimeConstant(referenceCache.parseValueTypeCached(type.getDescriptor())); } @@ -725,7 +725,7 @@ public class ProgramParser { pushConstant((Double) cst); } else if (cst instanceof String) { StringConstantInstruction insn = new StringConstantInstruction(); - insn.setConstant((String) cst); + insn.setConstant(referenceCache.getCached((String) cst)); insn.setReceiver(getVariable(pushSingle())); addInstruction(insn); } 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()) { case Opcodes.H_GETFIELD: - return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), - ValueType.parse(handle.getDesc())); + return MethodHandle.fieldGetter(owner, name, + referenceCache.getCached(ValueType.parse(handle.getDesc()))); case Opcodes.H_GETSTATIC: - return MethodHandle.staticFieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), - ValueType.parse(handle.getDesc())); + return MethodHandle.staticFieldGetter(owner, name, + referenceCache.getCached(ValueType.parse(handle.getDesc()))); case Opcodes.H_PUTFIELD: - return MethodHandle.fieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), - ValueType.parse(handle.getDesc())); + return MethodHandle.fieldSetter(owner, name, + referenceCache.getCached(ValueType.parse(handle.getDesc()))); case Opcodes.H_PUTSTATIC: - return MethodHandle.staticFieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), - ValueType.parse(handle.getDesc())); + return MethodHandle.staticFieldSetter(owner, name, + referenceCache.getCached(ValueType.parse(handle.getDesc()))); case Opcodes.H_INVOKEVIRTUAL: - return MethodHandle.virtualCaller(handle.getOwner().replace('/', '.'), handle.getName(), - MethodDescriptor.parseSignature(handle.getDesc())); + return MethodHandle.virtualCaller(owner, name, parseSignature(handle.getDesc())); case Opcodes.H_INVOKESTATIC: - return MethodHandle.staticCaller(handle.getOwner().replace('/', '.'), handle.getName(), - MethodDescriptor.parseSignature(handle.getDesc())); + return MethodHandle.staticCaller(owner, name, parseSignature(handle.getDesc())); case Opcodes.H_INVOKESPECIAL: - return MethodHandle.specialCaller(handle.getOwner().replace('/', '.'), handle.getName(), - MethodDescriptor.parseSignature(handle.getDesc())); + return MethodHandle.specialCaller(owner, name, parseSignature(handle.getDesc())); case Opcodes.H_NEWINVOKESPECIAL: - return MethodHandle.constructorCaller(handle.getOwner().replace('/', '.'), handle.getName(), - MethodDescriptor.parseSignature(handle.getDesc())); + return MethodHandle.constructorCaller(owner, name, parseSignature(handle.getDesc())); case Opcodes.H_INVOKEINTERFACE: - return MethodHandle.interfaceCaller(handle.getOwner().replace('/', '.'), handle.getName(), - MethodDescriptor.parseSignature(handle.getDesc())); + return MethodHandle.interfaceCaller(owner, name, parseSignature(handle.getDesc())); default: 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) { switch (fieldName) { case "java/lang/Boolean.TYPE": diff --git a/core/src/main/java/org/teavm/parsing/resource/ResourceClassHolderMapper.java b/core/src/main/java/org/teavm/parsing/resource/ResourceClassHolderMapper.java index ddab1814f..5de59f691 100644 --- a/core/src/main/java/org/teavm/parsing/resource/ResourceClassHolderMapper.java +++ b/core/src/main/java/org/teavm/parsing/resource/ResourceClassHolderMapper.java @@ -25,11 +25,12 @@ import org.teavm.model.ReferenceCache; import org.teavm.parsing.Parser; public class ResourceClassHolderMapper implements Mapper { - private Parser parser = new Parser(new ReferenceCache()); + private Parser parser; private ResourceReader resourceReader; - public ResourceClassHolderMapper(ResourceReader resourceReader) { + public ResourceClassHolderMapper(ResourceReader resourceReader, ReferenceCache referenceCache) { this.resourceReader = resourceReader; + parser = new Parser(referenceCache); } @Override diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 298093367..dc3c1d3c8 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -377,6 +377,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { cacheStatus = new AnnotationAwareCacheStatus(rawCacheStatus, dependencyAnalyzer.getIncrementalDependencies(), dependencyAnalyzer.getClassSource()); cacheStatus.addSynthesizedClasses(dependencyAnalyzer::isSynthesizedClass); + dependencyAnalyzer.setInterruptor(null); // Link if (wasCancelled()) { diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java index 2d0f37f2a..c978a5612 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSMethods.java @@ -18,6 +18,7 @@ package org.teavm.jso.impl; import java.util.Arrays; import java.util.function.Function; import org.teavm.jso.JSObject; +import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSArrayReader; import org.teavm.model.MethodReference; 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", 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]; static { diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java index 1a8396340..8efee5de0 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSValueMarshaller.java @@ -20,7 +20,6 @@ import java.util.function.Function; import org.teavm.diagnostics.Diagnostics; import org.teavm.jso.JSFunctor; import org.teavm.jso.JSObject; -import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSArrayReader; import org.teavm.model.CallLocation; import org.teavm.model.ClassReader; @@ -29,6 +28,7 @@ import org.teavm.model.ElementModifier; import org.teavm.model.Instruction; import org.teavm.model.MethodReference; import org.teavm.model.Program; +import org.teavm.model.ReferenceCache; import org.teavm.model.TextLocation; import org.teavm.model.ValueType; import org.teavm.model.Variable; @@ -39,6 +39,8 @@ import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.StringConstantInstruction; class JSValueMarshaller { + private static final ValueType stringType = ValueType.parse(String.class); + private ReferenceCache referenceCache = new ReferenceCache(); private Diagnostics diagnostics; private JSTypeHelper typeHelper; private ClassReaderSource classSource; @@ -123,8 +125,8 @@ class JSValueMarshaller { if (degree <= 1) { InvokeInstruction insn = new InvokeInstruction(); - insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type), - getWrapperType(type))); + insn.setMethod(referenceCache.getCached(new MethodReference(JS.class.getName(), "wrap", + getWrappedType(type), getWrapperType(type)))); insn.getArguments().add(var); insn.setReceiver(result); insn.setType(InvocationType.SPECIAL); @@ -152,8 +154,8 @@ class JSValueMarshaller { } insn = new InvokeInstruction(); - insn.setMethod(new MethodReference(JS.class.getName(), "map", getWrappedType(type), - ValueType.parse(Function.class), getWrapperType(type))); + insn.setMethod(referenceCache.getCached(new MethodReference(JS.class.getName(), "map", + getWrappedType(type), ValueType.parse(Function.class), getWrapperType(type)))); insn.getArguments().add(var); insn.getArguments().add(function); insn.setReceiver(result); @@ -176,7 +178,7 @@ class JSValueMarshaller { if (type.isObject(String.class)) { return type; } else { - return ValueType.parse(JSObject.class); + return JSMethods.JS_OBJECT; } } else { return type; @@ -185,9 +187,9 @@ class JSValueMarshaller { private ValueType getWrapperType(ValueType type) { if (type instanceof ValueType.Array) { - return ValueType.parse(JSArray.class); + return JSMethods.JS_ARRAY; } else { - return ValueType.parse(JSObject.class); + return JSMethods.JS_OBJECT; } } @@ -232,25 +234,25 @@ class JSValueMarshaller { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive) type).getKind()) { case BOOLEAN: - return unwrap(var, "unwrapBoolean", ValueType.parse(JSObject.class), ValueType.BOOLEAN, + return unwrap(var, "unwrapBoolean", JSMethods.JS_OBJECT, ValueType.BOOLEAN, location.getSourceLocation()); case BYTE: - return unwrap(var, "unwrapByte", ValueType.parse(JSObject.class), ValueType.BYTE, + return unwrap(var, "unwrapByte", JSMethods.JS_OBJECT, ValueType.BYTE, location.getSourceLocation()); case SHORT: - return unwrap(var, "unwrapShort", ValueType.parse(JSObject.class), ValueType.SHORT, + return unwrap(var, "unwrapShort", JSMethods.JS_OBJECT, ValueType.SHORT, location.getSourceLocation()); case INTEGER: - return unwrap(var, "unwrapInt", ValueType.parse(JSObject.class), ValueType.INTEGER, + return unwrap(var, "unwrapInt", JSMethods.JS_OBJECT, ValueType.INTEGER, location.getSourceLocation()); case CHARACTER: - return unwrap(var, "unwrapCharacter", ValueType.parse(JSObject.class), ValueType.CHARACTER, + return unwrap(var, "unwrapCharacter", JSMethods.JS_OBJECT, ValueType.CHARACTER, location.getSourceLocation()); case DOUBLE: - return unwrap(var, "unwrapDouble", ValueType.parse(JSObject.class), ValueType.DOUBLE, + return unwrap(var, "unwrapDouble", JSMethods.JS_OBJECT, ValueType.DOUBLE, location.getSourceLocation()); case FLOAT: - return unwrap(var, "unwrapFloat", ValueType.parse(JSObject.class), ValueType.FLOAT, + return unwrap(var, "unwrapFloat", JSMethods.JS_OBJECT, ValueType.FLOAT, location.getSourceLocation()); case LONG: break; @@ -260,8 +262,7 @@ class JSValueMarshaller { if (className.equals(JSObject.class.getName())) { return var; } else if (className.equals("java.lang.String")) { - return unwrap(var, "unwrapString", ValueType.parse(JSObject.class), ValueType.parse(String.class), - location.getSourceLocation()); + return unwrap(var, "unwrapString", JSMethods.JS_OBJECT, stringType, location.getSourceLocation()); } else if (typeHelper.isJavaScriptClass(className)) { Variable result = program.createVariable(); CastInstruction castInsn = new CastInstruction(); @@ -451,7 +452,8 @@ class JSValueMarshaller { } Variable result = program.createVariable(); 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.setReceiver(result); insn.setType(InvocationType.SPECIAL); @@ -482,7 +484,7 @@ class JSValueMarshaller { } 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) { diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingDependencyListener.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingDependencyListener.java index b2c02989b..f878493e3 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingDependencyListener.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingDependencyListener.java @@ -47,11 +47,21 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene MetaprogrammingImpl.classLoader = proxyClassLoader; MetaprogrammingImpl.classSource = agent.getClassSource(); MetaprogrammingImpl.hierarchy = agent.getClassHierarchy(); - MetaprogrammingImpl.incrementaDependencies = agent.getIncrementalCache(); + MetaprogrammingImpl.incrementalDependencies = agent.getIncrementalCache(); MetaprogrammingImpl.agent = agent; 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 public void methodReached(DependencyAgent agent, MethodDependency methodDep) { MethodModel proxy = describer.getMethod(methodDep.getReference()); diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java index 597997e3e..181b61806 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/MetaprogrammingImpl.java @@ -65,7 +65,7 @@ public final class MetaprogrammingImpl { static ClassLoader classLoader; static ClassReaderSource classSource; static ClassHierarchy hierarchy; - static IncrementalDependencyRegistration incrementaDependencies; + static IncrementalDependencyRegistration incrementalDependencies; static ReflectContext reflectContext; static DependencyAgent agent; static VariableContext varContext; @@ -320,7 +320,7 @@ public final class MetaprogrammingImpl { ValueImpl result = new ValueImpl<>(nestedVarContext.createInstance(generator), varContext, innerType); - incrementaDependencies.setNoCache(cls.getName()); + incrementalDependencies.setNoCache(cls.getName()); agent.submitClass(cls); return result; } diff --git a/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java index 67ef9cf93..4b0addd7d 100644 --- a/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java +++ b/platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java @@ -23,6 +23,19 @@ import org.teavm.platform.metadata.ResourceArray; import org.teavm.platform.metadata.ResourceMap; 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 Program program; @@ -97,14 +110,13 @@ class ResourceProgramTransformer { InvokeInstruction keysInsn = new InvokeInstruction(); keysInsn.setType(InvocationType.SPECIAL); - keysInsn.setMethod(new MethodReference(ResourceAccessor.class, "keys", Object.class, Object.class)); + keysInsn.setMethod(KEYS); keysInsn.getArguments().add(insn.getInstance()); keysInsn.setReceiver(tmp); InvokeInstruction transformInsn = new InvokeInstruction(); transformInsn.setType(InvocationType.SPECIAL); - transformInsn.setMethod(new MethodReference(ResourceAccessor.class, "keysToStrings", - Object.class, String[].class)); + transformInsn.setMethod(KEYS_TO_STRINGS); transformInsn.getArguments().add(tmp); transformInsn.setReceiver(insn.getReceiver()); @@ -148,8 +160,7 @@ class ResourceProgramTransformer { getProperty(insn, property, instructions, resultVar); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); - castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString", - Object.class, String.class)); + castInvoke.setMethod(CAST_TO_STRING); castInvoke.getArguments().add(resultVar); castInvoke.setReceiver(insn.getReceiver()); instructions.add(castInvoke); @@ -179,8 +190,7 @@ class ResourceProgramTransformer { instructions.add(nameInsn); InvokeInstruction accessorInvoke = new InvokeInstruction(); accessorInvoke.setType(InvocationType.SPECIAL); - accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "getProperty", - Object.class, String.class, Object.class)); + accessorInvoke.setMethod(GET_PROPERTY); accessorInvoke.getArguments().add(insn.getInstance()); accessorInvoke.getArguments().add(nameVar); accessorInvoke.setReceiver(resultVar); @@ -236,8 +246,7 @@ class ResourceProgramTransformer { Variable castVar = insn.getProgram().createVariable(); InvokeInstruction castInvoke = new InvokeInstruction(); castInvoke.setType(InvocationType.SPECIAL); - castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString", - String.class, Object.class)); + castInvoke.setMethod(CAST_FROM_STRING); castInvoke.getArguments().add(insn.getArguments().get(0)); castInvoke.setReceiver(castVar); instructions.add(castInvoke); @@ -262,8 +271,7 @@ class ResourceProgramTransformer { instructions.add(nameInsn); InvokeInstruction accessorInvoke = new InvokeInstruction(); accessorInvoke.setType(InvocationType.SPECIAL); - accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "put", - Object.class, String.class, Object.class, void.class)); + accessorInvoke.setMethod(PUT); accessorInvoke.getArguments().add(insn.getInstance()); accessorInvoke.getArguments().add(nameVar); accessorInvoke.getArguments().add(valueVar);