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.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("<init>", void.class);
private Map<String, List<String>> 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("<init>", 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("<init>", ValueType.VOID));
MethodReference ctor = new MethodReference(implementationType, INIT_METHOD);
agent.linkMethod(ctor).addLocation(location).use();
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.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<MethodReference, Integer> lambdaIdsByMethod = new HashMap<>();
private Map<MethodDescriptor, MethodDescriptor> descriptorCache = new HashMap<>();
private List<String> 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("<init>", signature);
MethodDescriptor descriptor = descriptorCache.computeIfAbsent(new MethodDescriptor("<init>", 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(), "<init>");
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)) {

View File

@ -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("<clinit>", 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("<clinit>", 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)) {

View File

@ -76,6 +76,7 @@ public class Renderer implements RenderingManager {
private RenderingContext context;
private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>();
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 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("<clinit>", 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("<clinit>", ValueType.VOID));
MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD);
if (clinit != null) {
writer.appendClassInit(cls.getName());
} else {

View File

@ -103,6 +103,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
private List<String> blockIds = new ArrayList<>();
private IntIndexedContainer blockIndexMap = new IntArrayList();
private boolean longLibraryUsed;
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", 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("<clinit>", void.class));
MethodReader method = cls.getMethod(CLINIT_METHOD);
if (method == null) {
return;
}

View File

@ -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<MethodReference, DefaultCallGraphNode> nodes = new LinkedHashMap<>();
Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new LinkedHashMap<>();
public Map<MethodReference, DefaultCallGraphNode> nodes = new HashMap<>();
Map<FieldReference, Set<DefaultFieldAccessSite>> fieldAccessSites = new HashMap<>();
@Override
public DefaultCallGraphNode getNode(MethodReference method) {

View File

@ -28,9 +28,11 @@ import org.teavm.model.TextLocation;
public class DefaultCallGraphNode implements CallGraphNode {
private DefaultCallGraph graph;
private MethodReference method;
private Set<DefaultCallSite> callSites = new LinkedHashSet<>(10, 0.5f);
private Set<DefaultCallSite> callSites;
private DefaultCallSite singleCallSite;
private Set<DefaultCallSite> safeCallSites;
private List<DefaultCallSite> callerCallSites = new ArrayList<>();
private DefaultCallSite singleCaller;
private List<DefaultCallSite> callerCallSites;
private List<DefaultCallSite> safeCallersCallSites;
private Set<DefaultFieldAccessSite> fieldAccessSites = new LinkedHashSet<>();
private Set<DefaultFieldAccessSite> safeFieldAccessSites;
@ -52,6 +54,12 @@ public class DefaultCallGraphNode implements CallGraphNode {
@Override
public Collection<DefaultCallSite> 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<DefaultCallSite> 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);
}

View File

@ -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) {

View File

@ -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();
}

View File

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

View File

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

View File

@ -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<Variable, CapturedValue> capturedValueMap = new HashMap<>();
private List<CapturedValue> capturedValues = new ArrayList<>();
private static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", 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(), "<init>", ValueType.VOID));
invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), INIT_METHOD));
invokeSuper.setType(InvocationType.SPECIAL);
ctorBlock.add(invokeSuper);