diff --git a/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java b/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java index 361084df4..2bea6a59f 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/ServiceLoaderSupport.java @@ -41,11 +41,11 @@ import org.teavm.dependency.MethodDependency; import org.teavm.model.CallLocation; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; -import org.teavm.model.ValueType; public class ServiceLoaderSupport extends AbstractDependencyListener implements Generator { private static final MethodReference LOAD_METHOD = new MethodReference(ServiceLoader.class, "load", Class.class, ServiceLoader.class); + private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("", void.class); private Map> serviceMap = new HashMap<>(); private ClassLoader classLoader; @@ -68,7 +68,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements String implName = implementations.get(i); if (context.getClassSource().getClassNames().contains(implName)) { writer.append("[").appendClass(implName).append(", ").appendMethodBody( - new MethodReference(implName, new MethodDescriptor("", ValueType.VOID))) + new MethodReference(implName, INIT_METHOD)) .append("]"); } } @@ -105,8 +105,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements } serviceMap.computeIfAbsent(type.getName(), k -> new ArrayList<>()).add(implementationType); - MethodReference ctor = new MethodReference(implementationType, - new MethodDescriptor("", ValueType.VOID)); + MethodReference ctor = new MethodReference(implementationType, INIT_METHOD); agent.linkMethod(ctor).addLocation(location).use(); method.getResult().getArrayItem().propagate(agent.getType(implementationType)); } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java index 4fbf9826b..1fa132c69 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java @@ -17,6 +17,7 @@ package org.teavm.classlib.impl.lambda; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,6 +30,7 @@ import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; import org.teavm.model.ElementModifier; import org.teavm.model.FieldHolder; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodHandle; import org.teavm.model.MethodHandleType; import org.teavm.model.MethodHolder; @@ -46,6 +48,8 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor private static final int FLAG_MARKERS = 2; private static final int FLAG_BRIDGES = 4; private Map lambdaIdsByMethod = new HashMap<>(); + private Map descriptorCache = new HashMap<>(); + private List fieldNameCache = new ArrayList<>(); @Override public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) { @@ -100,7 +104,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor ValueType[] implementorSignature = getSignature(implMethod); ValueEmitter[] passedArguments = new ValueEmitter[implementorSignature.length - 1]; for (int i = 0; i < capturedVarCount; ++i) { - passedArguments[i] = thisVar.getField("_" + i, invokedType[i]); + passedArguments[i] = thisVar.getField(fieldName(i), invokedType[i]); } for (int i = 0; i < instantiatedMethodType.length - 1; ++i) { passedArguments[i + capturedVarCount] = tryConvertArgument(arguments[i], instantiatedMethodType[i], @@ -298,7 +302,9 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor TextLocation location) { ValueType[] signature = Arrays.copyOf(types, types.length + 1); signature[types.length] = ValueType.VOID; - MethodHolder ctor = new MethodHolder("", signature); + MethodDescriptor descriptor = descriptorCache.computeIfAbsent(new MethodDescriptor("", signature), + k -> k); + MethodHolder ctor = new MethodHolder(descriptor); ctor.setLevel(AccessLevel.PUBLIC); ProgramEmitter pe = ProgramEmitter.create(ctor, hierarchy); @@ -307,7 +313,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor thisVar.invokeSpecial(implementor.getParent(), ""); for (int i = 0; i < types.length; ++i) { - FieldHolder field = new FieldHolder("_" + i); + FieldHolder field = new FieldHolder(fieldName(i)); field.setLevel(AccessLevel.PRIVATE); field.setType(types[i]); implementor.addField(field); @@ -319,6 +325,18 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor return ctor; } + private String fieldName(int index) { + if (index >= fieldNameCache.size()) { + fieldNameCache.addAll(Collections.nCopies(index - fieldNameCache.size() + 1, null)); + } + String result = fieldNameCache.get(index); + if (result == null) { + result = "_" + index; + fieldNameCache.set(index, result); + } + return result; + } + private void createBridge(ClassHierarchy hierarchy, ClassHolder implementor, String name, ValueType[] types, ValueType[] bridgeTypes, TextLocation location) { if (Arrays.equals(types, bridgeTypes)) { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java index aedf1b2ba..ef6ae3dea 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java @@ -59,6 +59,7 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit "monitorExit", Object.class, void.class); static final MethodReference MONITOR_EXIT_SYNC_METHOD = new MethodReference(Object.class, "monitorExitSync", Object.class, void.class); + private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("", ValueType.VOID); private final NameFrequencyConsumer consumer; private final ClassReaderSource classSource; @@ -88,8 +89,7 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit } // Methods - MethodReader clinit = classSource.get(cls.getName()).getMethod( - new MethodDescriptor("", ValueType.VOID)); + MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD); for (PreparedMethod method : cls.getMethods()) { consumer.consume(method.reference); if (asyncFamilyMethods.contains(method.reference)) { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index d46fb0108..fc827d9fd 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -76,6 +76,7 @@ public class Renderer implements RenderingManager { private RenderingContext context; private List postponedFieldInitializers = new ArrayList<>(); private IntFunction progressConsumer = p -> TeaVMProgressFeedback.CONTINUE; + private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("", ValueType.VOID); private ObjectIntMap sizeByClass = new ObjectIntHashMap<>(); private int stringPoolSize; @@ -376,8 +377,7 @@ public class Renderer implements RenderingManager { private void renderMethodBodies(PreparedClass cls) throws RenderingException { debugEmitter.emitClass(cls.getName()); try { - MethodReader clinit = classSource.get(cls.getName()).getMethod( - new MethodDescriptor("", ValueType.VOID)); + MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD); if (clinit != null) { renderCallClinit(clinit, cls); @@ -540,8 +540,7 @@ public class Renderer implements RenderingManager { writer.append(ElementModifier.pack(cls.getClassHolder().getModifiers())).append(',').ws(); writer.append(cls.getClassHolder().getLevel().ordinal()).append(',').ws(); - MethodReader clinit = classSource.get(cls.getName()).getMethod( - new MethodDescriptor("", ValueType.VOID)); + MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD); if (clinit != null) { writer.appendClassInit(cls.getName()); } else { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index 65eff3dc8..f229685d8 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -103,6 +103,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { private List blockIds = new ArrayList<>(); private IntIndexedContainer blockIndexMap = new IntArrayList(); private boolean longLibraryUsed; + private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("", ValueType.VOID); public StatementRenderer(RenderingContext context, SourceWriter writer) { this.context = context; @@ -462,7 +463,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { if (cls == null) { return; } - MethodReader method = cls.getMethod(new MethodDescriptor("", void.class)); + MethodReader method = cls.getMethod(CLINIT_METHOD); if (method == null) { return; } diff --git a/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java b/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java index 341a8a4aa..f6df3ea07 100644 --- a/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java +++ b/core/src/main/java/org/teavm/callgraph/DefaultCallGraph.java @@ -24,6 +24,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -33,8 +34,8 @@ import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; public class DefaultCallGraph implements CallGraph, Serializable { - Map nodes = new LinkedHashMap<>(); - Map> fieldAccessSites = new LinkedHashMap<>(); + public Map nodes = new HashMap<>(); + Map> fieldAccessSites = new HashMap<>(); @Override public DefaultCallGraphNode getNode(MethodReference method) { diff --git a/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java b/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java index 180edacdd..f150a8149 100644 --- a/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java +++ b/core/src/main/java/org/teavm/callgraph/DefaultCallGraphNode.java @@ -28,9 +28,11 @@ import org.teavm.model.TextLocation; public class DefaultCallGraphNode implements CallGraphNode { private DefaultCallGraph graph; private MethodReference method; - private Set callSites = new LinkedHashSet<>(10, 0.5f); + private Set callSites; + private DefaultCallSite singleCallSite; private Set safeCallSites; - private List callerCallSites = new ArrayList<>(); + private DefaultCallSite singleCaller; + private List callerCallSites; private List safeCallersCallSites; private Set fieldAccessSites = new LinkedHashSet<>(); private Set safeFieldAccessSites; @@ -52,6 +54,12 @@ public class DefaultCallGraphNode implements CallGraphNode { @Override public Collection getCallSites() { + if (callSites == null) { + if (singleCallSite != null) { + return Collections.singletonList(singleCallSite); + } + return Collections.emptyList(); + } if (safeCallSites == null) { safeCallSites = Collections.unmodifiableSet(callSites); } @@ -60,6 +68,12 @@ public class DefaultCallGraphNode implements CallGraphNode { @Override public Collection getCallerCallSites() { + if (callerCallSites == null) { + if (singleCaller != null) { + return Collections.singletonList(singleCaller); + } + return Collections.emptyList(); + } if (safeCallersCallSites == null) { safeCallersCallSites = Collections.unmodifiableList(callerCallSites); } @@ -69,14 +83,37 @@ public class DefaultCallGraphNode implements CallGraphNode { public boolean addCallSite(MethodReference method, TextLocation location) { DefaultCallGraphNode callee = graph.getNode(method); DefaultCallSite callSite = new DefaultCallSite(location, callee, this); + if (callSites == null) { + if (singleCallSite == null) { + singleCallSite = callSite; + callee.addCaller(callSite); + return true; + } + callSites = new LinkedHashSet<>(); + callSites.add(singleCallSite); + singleCallSite = null; + } if (callSites.add(callSite)) { - callee.callerCallSites.add(callSite); + callee.addCaller(callSite); return true; } else { return false; } } + private void addCaller(DefaultCallSite caller) { + if (callerCallSites == null) { + if (singleCaller == null) { + singleCaller = caller; + return; + } + callerCallSites = new ArrayList<>(); + callerCallSites.add(singleCaller); + singleCaller = null; + } + callerCallSites.add(caller); + } + public boolean addCallSite(MethodReference method) { return addCallSite(method, null); } diff --git a/core/src/main/java/org/teavm/model/ReferenceCache.java b/core/src/main/java/org/teavm/model/ReferenceCache.java index 939bcc487..dcc813799 100644 --- a/core/src/main/java/org/teavm/model/ReferenceCache.java +++ b/core/src/main/java/org/teavm/model/ReferenceCache.java @@ -35,7 +35,7 @@ public class ReferenceCache { public MethodReference getCached(String className, MethodDescriptor descriptor) { return referenceCache .computeIfAbsent(className, key -> new HashMap<>()) - .computeIfAbsent(descriptor, key -> new MethodReference(className, descriptor)); + .computeIfAbsent(getCached(descriptor), key -> new MethodReference(className, key)); } public MethodDescriptor getCached(MethodDescriptor descriptor) { diff --git a/core/src/main/java/org/teavm/model/emit/ValueEmitter.java b/core/src/main/java/org/teavm/model/emit/ValueEmitter.java index 657bb19a0..4a86fe311 100644 --- a/core/src/main/java/org/teavm/model/emit/ValueEmitter.java +++ b/core/src/main/java/org/teavm/model/emit/ValueEmitter.java @@ -17,8 +17,11 @@ package org.teavm.model.emit; import org.teavm.model.BasicBlock; import org.teavm.model.ClassHierarchy; +import org.teavm.model.ClassReader; import org.teavm.model.FieldReference; import org.teavm.model.Incoming; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.Phi; import org.teavm.model.PrimitiveType; @@ -467,7 +470,11 @@ public class ValueEmitter { } signature[arguments.length] = resultType; - MethodReference method = new MethodReference(className, name, signature); + ClassReader cls = pe.classSource.get(className); + MethodReader methodReader = cls != null ? cls.getMethod(new MethodDescriptor(name, signature)) : null; + MethodReference method = methodReader != null + ? methodReader.getReference() + : new MethodReference(className, name, signature); if (method.getReturnType() != ValueType.VOID) { result = pe.getProgram().createVariable(); } diff --git a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index 2d00ad362..051147d1a 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -51,6 +51,7 @@ public class AsyncProgramSplitter { private ClassReaderSource classSource; private Set asyncMethods; private Program program; + private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("", ValueType.VOID); public AsyncProgramSplitter(ClassReaderSource classSource, Set asyncMethods) { this.classSource = classSource; @@ -211,7 +212,7 @@ public class AsyncProgramSplitter { return false; } - MethodReader method = cls.getMethod(new MethodDescriptor("", ValueType.VOID)); + MethodReader method = cls.getMethod(CLINIT_METHOD); return method != null && asyncMethods.contains(method.getReference()); } diff --git a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index 5c0a34dec..599941099 100644 --- a/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -33,7 +33,6 @@ import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.MethodDescriptor; 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; @@ -108,7 +107,8 @@ public class ClassRefsRenamer extends AbstractInstructionVisitor { for (int i = 0; i < signature.length; ++i) { signature[i] = rename(signature[i]); } - MethodHolder renamedMethod = new MethodHolder(methodName, signature); + MethodHolder renamedMethod = new MethodHolder(referenceCache.getCached( + new MethodDescriptor(methodName, signature))); renamedMethod.getModifiers().addAll(method.getModifiers()); renamedMethod.setLevel(method.getLevel()); renamedMethod.setProgram(method.getProgram()); @@ -274,8 +274,8 @@ public class ClassRefsRenamer extends AbstractInstructionVisitor { signature[i] = newType; } if (changed) { - insn.setMethod(referenceCache.getCached(new MethodReference(className, - new MethodDescriptor(insn.getMethod().getName(), signature)))); + insn.setMethod(referenceCache.getCached(className, + new MethodDescriptor(insn.getMethod().getName(), signature))); } } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 5905f3486..c01562371 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -463,6 +463,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return null; } + dependencyAnalyzer.cleanup(); + return classSet; } diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java index d91882753..711b07f57 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/ProxyVariableContext.java @@ -24,6 +24,7 @@ import org.teavm.model.BasicBlock; import org.teavm.model.CallLocation; import org.teavm.model.ClassHolder; import org.teavm.model.FieldHolder; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodHolder; import org.teavm.model.MethodReference; import org.teavm.model.Program; @@ -43,6 +44,7 @@ public class ProxyVariableContext extends VariableContext { private int suffixGenerator; private Map capturedValueMap = new HashMap<>(); private List capturedValues = new ArrayList<>(); + private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("", ValueType.VOID); public ProxyVariableContext(VariableContext parent, ClassHolder proxyClass) { super(parent); @@ -103,7 +105,7 @@ public class ProxyVariableContext extends VariableContext { InvokeInstruction invokeSuper = new InvokeInstruction(); invokeSuper.setInstance(ctorProgram.createVariable()); - invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "", ValueType.VOID)); + invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), INIT_METHOD)); invokeSuper.setType(InvocationType.SPECIAL); ctorBlock.add(invokeSuper);