Trying to decrease compiler memory consumption

This commit is contained in:
Alexey Andreev 2019-02-25 18:31:34 +03:00
parent 84b4133989
commit 2c40c7d56e
13 changed files with 94 additions and 27 deletions

View File

@ -41,11 +41,11 @@ import org.teavm.dependency.MethodDependency;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ServiceLoaderSupport extends AbstractDependencyListener implements Generator { public class ServiceLoaderSupport extends AbstractDependencyListener implements Generator {
private static final MethodReference LOAD_METHOD = new MethodReference(ServiceLoader.class, "load", Class.class, private static final MethodReference LOAD_METHOD = new MethodReference(ServiceLoader.class, "load", Class.class,
ServiceLoader.class); ServiceLoader.class);
private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", void.class);
private Map<String, List<String>> serviceMap = new HashMap<>(); private Map<String, List<String>> serviceMap = new HashMap<>();
private ClassLoader classLoader; private ClassLoader classLoader;
@ -68,7 +68,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
String implName = implementations.get(i); String implName = implementations.get(i);
if (context.getClassSource().getClassNames().contains(implName)) { if (context.getClassSource().getClassNames().contains(implName)) {
writer.append("[").appendClass(implName).append(", ").appendMethodBody( writer.append("[").appendClass(implName).append(", ").appendMethodBody(
new MethodReference(implName, new MethodDescriptor("<init>", ValueType.VOID))) new MethodReference(implName, INIT_METHOD))
.append("]"); .append("]");
} }
} }
@ -105,8 +105,7 @@ public class ServiceLoaderSupport extends AbstractDependencyListener implements
} }
serviceMap.computeIfAbsent(type.getName(), k -> new ArrayList<>()).add(implementationType); serviceMap.computeIfAbsent(type.getName(), k -> new ArrayList<>()).add(implementationType);
MethodReference ctor = new MethodReference(implementationType, MethodReference ctor = new MethodReference(implementationType, INIT_METHOD);
new MethodDescriptor("<init>", ValueType.VOID));
agent.linkMethod(ctor).addLocation(location).use(); agent.linkMethod(ctor).addLocation(location).use();
method.getResult().getArrayItem().propagate(agent.getType(implementationType)); method.getResult().getArrayItem().propagate(agent.getType(implementationType));
} }

View File

@ -17,6 +17,7 @@ package org.teavm.classlib.impl.lambda;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -29,6 +30,7 @@ import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.FieldHolder; import org.teavm.model.FieldHolder;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHandle; import org.teavm.model.MethodHandle;
import org.teavm.model.MethodHandleType; import org.teavm.model.MethodHandleType;
import org.teavm.model.MethodHolder; 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_MARKERS = 2;
private static final int FLAG_BRIDGES = 4; private static final int FLAG_BRIDGES = 4;
private Map<MethodReference, Integer> lambdaIdsByMethod = new HashMap<>(); private Map<MethodReference, Integer> lambdaIdsByMethod = new HashMap<>();
private Map<MethodDescriptor, MethodDescriptor> descriptorCache = new HashMap<>();
private List<String> fieldNameCache = new ArrayList<>();
@Override @Override
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) { public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) {
@ -100,7 +104,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
ValueType[] implementorSignature = getSignature(implMethod); ValueType[] implementorSignature = getSignature(implMethod);
ValueEmitter[] passedArguments = new ValueEmitter[implementorSignature.length - 1]; ValueEmitter[] passedArguments = new ValueEmitter[implementorSignature.length - 1];
for (int i = 0; i < capturedVarCount; ++i) { 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) { for (int i = 0; i < instantiatedMethodType.length - 1; ++i) {
passedArguments[i + capturedVarCount] = tryConvertArgument(arguments[i], instantiatedMethodType[i], passedArguments[i + capturedVarCount] = tryConvertArgument(arguments[i], instantiatedMethodType[i],
@ -298,7 +302,9 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
TextLocation location) { TextLocation location) {
ValueType[] signature = Arrays.copyOf(types, types.length + 1); ValueType[] signature = Arrays.copyOf(types, types.length + 1);
signature[types.length] = ValueType.VOID; signature[types.length] = ValueType.VOID;
MethodHolder ctor = new MethodHolder("<init>", signature); MethodDescriptor descriptor = descriptorCache.computeIfAbsent(new MethodDescriptor("<init>", signature),
k -> k);
MethodHolder ctor = new MethodHolder(descriptor);
ctor.setLevel(AccessLevel.PUBLIC); ctor.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(ctor, hierarchy); ProgramEmitter pe = ProgramEmitter.create(ctor, hierarchy);
@ -307,7 +313,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
thisVar.invokeSpecial(implementor.getParent(), "<init>"); thisVar.invokeSpecial(implementor.getParent(), "<init>");
for (int i = 0; i < types.length; ++i) { for (int i = 0; i < types.length; ++i) {
FieldHolder field = new FieldHolder("_" + i); FieldHolder field = new FieldHolder(fieldName(i));
field.setLevel(AccessLevel.PRIVATE); field.setLevel(AccessLevel.PRIVATE);
field.setType(types[i]); field.setType(types[i]);
implementor.addField(field); implementor.addField(field);
@ -319,6 +325,18 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
return ctor; 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, private void createBridge(ClassHierarchy hierarchy, ClassHolder implementor, String name, ValueType[] types,
ValueType[] bridgeTypes, TextLocation location) { ValueType[] bridgeTypes, TextLocation location) {
if (Arrays.equals(types, bridgeTypes)) { if (Arrays.equals(types, bridgeTypes)) {

View File

@ -59,6 +59,7 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
"monitorExit", Object.class, void.class); "monitorExit", Object.class, void.class);
static final MethodReference MONITOR_EXIT_SYNC_METHOD = new MethodReference(Object.class, static final MethodReference MONITOR_EXIT_SYNC_METHOD = new MethodReference(Object.class,
"monitorExitSync", Object.class, void.class); "monitorExitSync", Object.class, void.class);
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", ValueType.VOID);
private final NameFrequencyConsumer consumer; private final NameFrequencyConsumer consumer;
private final ClassReaderSource classSource; private final ClassReaderSource classSource;
@ -88,8 +89,7 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
} }
// Methods // Methods
MethodReader clinit = classSource.get(cls.getName()).getMethod( MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD);
new MethodDescriptor("<clinit>", ValueType.VOID));
for (PreparedMethod method : cls.getMethods()) { for (PreparedMethod method : cls.getMethods()) {
consumer.consume(method.reference); consumer.consume(method.reference);
if (asyncFamilyMethods.contains(method.reference)) { if (asyncFamilyMethods.contains(method.reference)) {

View File

@ -76,6 +76,7 @@ public class Renderer implements RenderingManager {
private RenderingContext context; private RenderingContext context;
private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>(); private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>();
private IntFunction<TeaVMProgressFeedback> progressConsumer = p -> TeaVMProgressFeedback.CONTINUE; private IntFunction<TeaVMProgressFeedback> progressConsumer = p -> TeaVMProgressFeedback.CONTINUE;
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", ValueType.VOID);
private ObjectIntMap<String> sizeByClass = new ObjectIntHashMap<>(); private ObjectIntMap<String> sizeByClass = new ObjectIntHashMap<>();
private int stringPoolSize; private int stringPoolSize;
@ -376,8 +377,7 @@ public class Renderer implements RenderingManager {
private void renderMethodBodies(PreparedClass cls) throws RenderingException { private void renderMethodBodies(PreparedClass cls) throws RenderingException {
debugEmitter.emitClass(cls.getName()); debugEmitter.emitClass(cls.getName());
try { try {
MethodReader clinit = classSource.get(cls.getName()).getMethod( MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD);
new MethodDescriptor("<clinit>", ValueType.VOID));
if (clinit != null) { if (clinit != null) {
renderCallClinit(clinit, cls); renderCallClinit(clinit, cls);
@ -540,8 +540,7 @@ public class Renderer implements RenderingManager {
writer.append(ElementModifier.pack(cls.getClassHolder().getModifiers())).append(',').ws(); writer.append(ElementModifier.pack(cls.getClassHolder().getModifiers())).append(',').ws();
writer.append(cls.getClassHolder().getLevel().ordinal()).append(',').ws(); writer.append(cls.getClassHolder().getLevel().ordinal()).append(',').ws();
MethodReader clinit = classSource.get(cls.getName()).getMethod( MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD);
new MethodDescriptor("<clinit>", ValueType.VOID));
if (clinit != null) { if (clinit != null) {
writer.appendClassInit(cls.getName()); writer.appendClassInit(cls.getName());
} else { } else {

View File

@ -103,6 +103,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
private List<String> blockIds = new ArrayList<>(); private List<String> blockIds = new ArrayList<>();
private IntIndexedContainer blockIndexMap = new IntArrayList(); private IntIndexedContainer blockIndexMap = new IntArrayList();
private boolean longLibraryUsed; private boolean longLibraryUsed;
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", ValueType.VOID);
public StatementRenderer(RenderingContext context, SourceWriter writer) { public StatementRenderer(RenderingContext context, SourceWriter writer) {
this.context = context; this.context = context;
@ -462,7 +463,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
if (cls == null) { if (cls == null) {
return; return;
} }
MethodReader method = cls.getMethod(new MethodDescriptor("<clinit>", void.class)); MethodReader method = cls.getMethod(CLINIT_METHOD);
if (method == null) { if (method == null) {
return; return;
} }

View File

@ -24,6 +24,7 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
@ -33,8 +34,8 @@ import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class DefaultCallGraph implements CallGraph, Serializable { public class DefaultCallGraph implements CallGraph, Serializable {
Map<MethodReference, DefaultCallGraphNode> nodes = new LinkedHashMap<>(); public Map<MethodReference, DefaultCallGraphNode> nodes = new HashMap<>();
Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new LinkedHashMap<>(); Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new HashMap<>();
@Override @Override
public DefaultCallGraphNode getNode(MethodReference method) { public DefaultCallGraphNode getNode(MethodReference method) {

View File

@ -28,9 +28,11 @@ import org.teavm.model.TextLocation;
public class DefaultCallGraphNode implements CallGraphNode { public class DefaultCallGraphNode implements CallGraphNode {
private DefaultCallGraph graph; private DefaultCallGraph graph;
private MethodReference method; private MethodReference method;
private Set<DefaultCallSite> callSites = new LinkedHashSet<>(10, 0.5f); private Set<DefaultCallSite> callSites;
private DefaultCallSite singleCallSite;
private Set<DefaultCallSite> safeCallSites; private Set<DefaultCallSite> safeCallSites;
private List<DefaultCallSite> callerCallSites = new ArrayList<>(); private DefaultCallSite singleCaller;
private List<DefaultCallSite> callerCallSites;
private List<DefaultCallSite> safeCallersCallSites; private List<DefaultCallSite> safeCallersCallSites;
private Set<DefaultFieldAccessSite> fieldAccessSites = new LinkedHashSet<>(); private Set<DefaultFieldAccessSite> fieldAccessSites = new LinkedHashSet<>();
private Set<DefaultFieldAccessSite> safeFieldAccessSites; private Set<DefaultFieldAccessSite> safeFieldAccessSites;
@ -52,6 +54,12 @@ public class DefaultCallGraphNode implements CallGraphNode {
@Override @Override
public Collection<DefaultCallSite> getCallSites() { public Collection<DefaultCallSite> getCallSites() {
if (callSites == null) {
if (singleCallSite != null) {
return Collections.singletonList(singleCallSite);
}
return Collections.emptyList();
}
if (safeCallSites == null) { if (safeCallSites == null) {
safeCallSites = Collections.unmodifiableSet(callSites); safeCallSites = Collections.unmodifiableSet(callSites);
} }
@ -60,6 +68,12 @@ public class DefaultCallGraphNode implements CallGraphNode {
@Override @Override
public Collection<DefaultCallSite> getCallerCallSites() { public Collection<DefaultCallSite> getCallerCallSites() {
if (callerCallSites == null) {
if (singleCaller != null) {
return Collections.singletonList(singleCaller);
}
return Collections.emptyList();
}
if (safeCallersCallSites == null) { if (safeCallersCallSites == null) {
safeCallersCallSites = Collections.unmodifiableList(callerCallSites); safeCallersCallSites = Collections.unmodifiableList(callerCallSites);
} }
@ -69,14 +83,37 @@ public class DefaultCallGraphNode implements CallGraphNode {
public boolean addCallSite(MethodReference method, TextLocation location) { public boolean addCallSite(MethodReference method, TextLocation location) {
DefaultCallGraphNode callee = graph.getNode(method); DefaultCallGraphNode callee = graph.getNode(method);
DefaultCallSite callSite = new DefaultCallSite(location, callee, this); 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)) { if (callSites.add(callSite)) {
callee.callerCallSites.add(callSite); callee.addCaller(callSite);
return true; return true;
} else { } else {
return false; 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) { public boolean addCallSite(MethodReference method) {
return addCallSite(method, null); return addCallSite(method, null);
} }

View File

@ -35,7 +35,7 @@ public class ReferenceCache {
public MethodReference getCached(String className, MethodDescriptor descriptor) { public MethodReference getCached(String className, MethodDescriptor descriptor) {
return referenceCache return referenceCache
.computeIfAbsent(className, key -> new HashMap<>()) .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) { public MethodDescriptor getCached(MethodDescriptor descriptor) {

View File

@ -17,8 +17,11 @@ package org.teavm.model.emit;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReader;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.Incoming; import org.teavm.model.Incoming;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.PrimitiveType; import org.teavm.model.PrimitiveType;
@ -467,7 +470,11 @@ public class ValueEmitter {
} }
signature[arguments.length] = resultType; 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) { if (method.getReturnType() != ValueType.VOID) {
result = pe.getProgram().createVariable(); result = pe.getProgram().createVariable();
} }

View File

@ -51,6 +51,7 @@ public class AsyncProgramSplitter {
private ClassReaderSource classSource; private ClassReaderSource classSource;
private Set<MethodReference> asyncMethods; private Set<MethodReference> asyncMethods;
private Program program; private Program program;
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", ValueType.VOID);
public AsyncProgramSplitter(ClassReaderSource classSource, Set<MethodReference> asyncMethods) { public AsyncProgramSplitter(ClassReaderSource classSource, Set<MethodReference> asyncMethods) {
this.classSource = classSource; this.classSource = classSource;
@ -211,7 +212,7 @@ public class AsyncProgramSplitter {
return false; return false;
} }
MethodReader method = cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)); MethodReader method = cls.getMethod(CLINIT_METHOD);
return method != null && asyncMethods.contains(method.getReference()); return method != null && asyncMethods.contains(method.getReference());
} }

View File

@ -33,7 +33,6 @@ import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHandle; import org.teavm.model.MethodHandle;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ReferenceCache; import org.teavm.model.ReferenceCache;
import org.teavm.model.RuntimeConstant; import org.teavm.model.RuntimeConstant;
@ -108,7 +107,8 @@ public class ClassRefsRenamer extends AbstractInstructionVisitor {
for (int i = 0; i < signature.length; ++i) { for (int i = 0; i < signature.length; ++i) {
signature[i] = rename(signature[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.getModifiers().addAll(method.getModifiers());
renamedMethod.setLevel(method.getLevel()); renamedMethod.setLevel(method.getLevel());
renamedMethod.setProgram(method.getProgram()); renamedMethod.setProgram(method.getProgram());
@ -274,8 +274,8 @@ public class ClassRefsRenamer extends AbstractInstructionVisitor {
signature[i] = newType; signature[i] = newType;
} }
if (changed) { if (changed) {
insn.setMethod(referenceCache.getCached(new MethodReference(className, insn.setMethod(referenceCache.getCached(className,
new MethodDescriptor(insn.getMethod().getName(), signature)))); new MethodDescriptor(insn.getMethod().getName(), signature)));
} }
} }

View File

@ -463,6 +463,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return null; return null;
} }
dependencyAnalyzer.cleanup();
return classSet; return classSet;
} }

View File

@ -24,6 +24,7 @@ import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.FieldHolder; import org.teavm.model.FieldHolder;
import org.teavm.model.MethodDescriptor;
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;
@ -43,6 +44,7 @@ public class ProxyVariableContext extends VariableContext {
private int suffixGenerator; private int suffixGenerator;
private Map<Variable, CapturedValue> capturedValueMap = new HashMap<>(); private Map<Variable, CapturedValue> capturedValueMap = new HashMap<>();
private List<CapturedValue> capturedValues = new ArrayList<>(); private List<CapturedValue> capturedValues = new ArrayList<>();
private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", ValueType.VOID);
public ProxyVariableContext(VariableContext parent, ClassHolder proxyClass) { public ProxyVariableContext(VariableContext parent, ClassHolder proxyClass) {
super(parent); super(parent);
@ -103,7 +105,7 @@ public class ProxyVariableContext extends VariableContext {
InvokeInstruction invokeSuper = new InvokeInstruction(); InvokeInstruction invokeSuper = new InvokeInstruction();
invokeSuper.setInstance(ctorProgram.createVariable()); invokeSuper.setInstance(ctorProgram.createVariable());
invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "<init>", ValueType.VOID)); invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), INIT_METHOD));
invokeSuper.setType(InvocationType.SPECIAL); invokeSuper.setType(InvocationType.SPECIAL);
ctorBlock.add(invokeSuper); ctorBlock.add(invokeSuper);