Use class/method names to generate lambda class names. Reduce number of types propagated by dependency analyzer

This commit is contained in:
Alexey Andreev 2018-06-29 16:46:36 +03:00
parent 2eea5cba5e
commit f160ce2f2f
6 changed files with 53 additions and 11 deletions

View File

@ -16,6 +16,8 @@
package org.teavm.classlib.impl.lambda; package org.teavm.classlib.impl.lambda;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.teavm.cache.NoCache; import org.teavm.cache.NoCache;
import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DynamicCallSite; import org.teavm.dependency.DynamicCallSite;
@ -29,6 +31,7 @@ import org.teavm.model.FieldHolder;
import org.teavm.model.MethodHandle; import org.teavm.model.MethodHandle;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.PrimitiveType; import org.teavm.model.PrimitiveType;
import org.teavm.model.TextLocation;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter; import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter; import org.teavm.model.emit.ValueEmitter;
@ -37,7 +40,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
private static final int FLAG_SERIALIZABLE = 1; private static final int FLAG_SERIALIZABLE = 1;
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 int lambdaIndex; private Map<String, Integer> lambdaIdsByMethod = new HashMap<>();
@Override @Override
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) { public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) {
@ -50,7 +53,11 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
ClassReaderSource classSource = callSite.getAgent().getClassSource(); ClassReaderSource classSource = callSite.getAgent().getClassSource();
ClassReader samClass = classSource.get(samName); ClassReader samClass = classSource.get(samName);
ClassHolder implementor = new ClassHolder("$$LAMBDA" + (lambdaIndex++) + "$$"); String key = callSite.getCaller().getClassName() + "$" + callSite.getCaller().getName();
int id = lambdaIdsByMethod.getOrDefault(key, 0);
lambdaIdsByMethod.put(key, id + 1);
ClassHolder implementor = new ClassHolder(key + "$lambda$_" + id);
implementor.setLevel(AccessLevel.PUBLIC); implementor.setLevel(AccessLevel.PUBLIC);
if (samClass != null && samClass.hasModifier(ElementModifier.INTERFACE)) { if (samClass != null && samClass.hasModifier(ElementModifier.INTERFACE)) {
implementor.setParent("java.lang.Object"); implementor.setParent("java.lang.Object");
@ -61,15 +68,16 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
int capturedVarCount = callSite.getCalledMethod().parameterCount(); int capturedVarCount = callSite.getCalledMethod().parameterCount();
MethodHolder ctor = createConstructor(classSource, implementor, MethodHolder ctor = createConstructor(classSource, implementor,
Arrays.copyOfRange(invokedType, 0, capturedVarCount)); Arrays.copyOfRange(invokedType, 0, capturedVarCount), callerPe.getCurrentLocation());
ctor.getAnnotations().add(new AnnotationHolder(NoCache.class.getName())); ctor.getAnnotations().add(new AnnotationHolder(NoCache.class.getName()));
createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType,
samMethodType); samMethodType, callerPe.getCurrentLocation());
MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType); MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType);
worker.getAnnotations().add(new AnnotationHolder(NoCache.class.getName())); worker.getAnnotations().add(new AnnotationHolder(NoCache.class.getName()));
worker.setLevel(AccessLevel.PUBLIC); worker.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(worker, callSite.getAgent().getClassSource()); ProgramEmitter pe = ProgramEmitter.create(worker, callSite.getAgent().getClassSource());
pe.setCurrentLocation(callerPe.getCurrentLocation());
ValueEmitter thisVar = pe.var(0, implementor); ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1]; ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1];
for (int i = 0; i < arguments.length; ++i) { for (int i = 0; i < arguments.length; ++i) {
@ -119,7 +127,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
for (int i = 0; i < bridgeCount; ++i) { for (int i = 0; i < bridgeCount; ++i) {
ValueType[] bridgeType = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getMethodType(); ValueType[] bridgeType = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getMethodType();
createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType,
bridgeType); bridgeType, callerPe.getCurrentLocation());
} }
} }
} }
@ -259,13 +267,15 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
} }
} }
private MethodHolder createConstructor(ClassReaderSource classSource, ClassHolder implementor, ValueType[] types) { private MethodHolder createConstructor(ClassReaderSource classSource, ClassHolder implementor, ValueType[] types,
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); MethodHolder ctor = new MethodHolder("<init>", signature);
ctor.setLevel(AccessLevel.PUBLIC); ctor.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(ctor, classSource); ProgramEmitter pe = ProgramEmitter.create(ctor, classSource);
pe.setCurrentLocation(location);
ValueEmitter thisVar = pe.var(0, implementor); ValueEmitter thisVar = pe.var(0, implementor);
thisVar.invokeSpecial(implementor.getParent(), "<init>"); thisVar.invokeSpecial(implementor.getParent(), "<init>");
@ -283,7 +293,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
} }
private void createBridge(ClassReaderSource classSource, ClassHolder implementor, String name, ValueType[] types, private void createBridge(ClassReaderSource classSource, ClassHolder implementor, String name, ValueType[] types,
ValueType[] bridgeTypes) { ValueType[] bridgeTypes, TextLocation location) {
if (Arrays.equals(types, bridgeTypes)) { if (Arrays.equals(types, bridgeTypes)) {
return; return;
} }
@ -293,6 +303,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
bridge.setLevel(AccessLevel.PUBLIC); bridge.setLevel(AccessLevel.PUBLIC);
bridge.getModifiers().add(ElementModifier.BRIDGE); bridge.getModifiers().add(ElementModifier.BRIDGE);
ProgramEmitter pe = ProgramEmitter.create(bridge, classSource); ProgramEmitter pe = ProgramEmitter.create(bridge, classSource);
pe.setCurrentLocation(location);
ValueEmitter thisVar = pe.var(0, implementor); ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1]; ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1];
for (int i = 0; i < arguments.length; ++i) { for (int i = 0; i < arguments.length; ++i) {

View File

@ -49,6 +49,17 @@ public class DefaultAliasProvider implements AliasProvider {
} }
} }
for (int i = 1; i < alias.length(); ++i) {
char c = alias.charAt(i);
if (!Character.isJavaIdentifierPart(c)) {
alias.setCharAt(i, '_');
}
}
if (!Character.isJavaIdentifierStart(alias.charAt(0))) {
alias.setCharAt(0, '_');
}
return makeUnique(knownAliases, alias.toString()); return makeUnique(knownAliases, alias.toString());
}); });
} }

View File

@ -435,7 +435,7 @@ public class DependencyAnalyzer implements DependencyInfo {
if (methodRef.getDescriptor().getResultType() == ValueType.VOID) { if (methodRef.getDescriptor().getResultType() == ValueType.VOID) {
resultNode = null; resultNode = null;
} else { } else {
resultNode = createNode(); resultNode = createNode(methodRef.getDescriptor().getResultType());
resultNode.method = methodRef; resultNode.method = methodRef;
if (shouldTag) { if (shouldTag) {
resultNode.setTag(methodRef + ":RESULT"); resultNode.setTag(methodRef + ":RESULT");

View File

@ -242,7 +242,8 @@ class DependencyGraphBuilder {
for (int k = 0; k < indy.getArguments().size(); ++k) { for (int k = 0; k < indy.getArguments().size(); ++k) {
arguments.add(pe.var(indy.getArguments().get(k), indy.getMethod().parameterType(k))); arguments.add(pe.var(indy.getArguments().get(k), indy.getMethod().parameterType(k)));
} }
DynamicCallSite callSite = new DynamicCallSite(indy.getMethod(), DynamicCallSite callSite = new DynamicCallSite(
methodDep.getReference(), indy.getMethod(),
indy.getInstance() != null ? pe.var(indy.getInstance(), indy.getInstance() != null ? pe.var(indy.getInstance(),
ValueType.object(methodDep.getMethod().getOwnerName())) : null, ValueType.object(methodDep.getMethod().getOwnerName())) : null,
arguments, indy.getBootstrapMethod(), indy.getBootstrapArguments(), arguments, indy.getBootstrapMethod(), indy.getBootstrapArguments(),
@ -579,6 +580,9 @@ class DependencyGraphBuilder {
@Override @Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index, public void getElement(VariableReader receiver, VariableReader array, VariableReader index,
ArrayElementType type) { ArrayElementType type) {
if (isPrimitive(type)) {
return;
}
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()];
if (arrayNode != null && receiverNode != null && receiverNode != arrayNode.getArrayItem()) { if (arrayNode != null && receiverNode != null && receiverNode != arrayNode.getArrayItem()) {
@ -589,6 +593,9 @@ class DependencyGraphBuilder {
@Override @Override
public void putElement(VariableReader array, VariableReader index, VariableReader value, public void putElement(VariableReader array, VariableReader index, VariableReader value,
ArrayElementType type) { ArrayElementType type) {
if (isPrimitive(type)) {
return;
}
DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()];
if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) { if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) {
@ -596,6 +603,10 @@ class DependencyGraphBuilder {
} }
} }
private boolean isPrimitive(ArrayElementType type) {
return type != ArrayElementType.OBJECT;
}
@Override @Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) { List<? extends VariableReader> arguments, InvocationType type) {

View File

@ -268,6 +268,7 @@ public class DependencyNode implements ValueDependencyInfo {
? ((ValueType.Array) typeFilter).getItemType() ? ((ValueType.Array) typeFilter).getItemType()
: null; : null;
arrayItemNode = new DependencyNode(dependencyAnalyzer, itemTypeFilter, degree + 1); arrayItemNode = new DependencyNode(dependencyAnalyzer, itemTypeFilter, degree + 1);
arrayItemNode.method = method;
if (DependencyAnalyzer.shouldTag) { if (DependencyAnalyzer.shouldTag) {
arrayItemNode.tag = tag + "["; arrayItemNode.tag = tag + "[";
} }

View File

@ -20,10 +20,12 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHandle; import org.teavm.model.MethodHandle;
import org.teavm.model.MethodReference;
import org.teavm.model.RuntimeConstant; import org.teavm.model.RuntimeConstant;
import org.teavm.model.emit.ValueEmitter; import org.teavm.model.emit.ValueEmitter;
public class DynamicCallSite { public class DynamicCallSite {
private MethodReference caller;
private MethodDescriptor calledMethod; private MethodDescriptor calledMethod;
private ValueEmitter instance; private ValueEmitter instance;
private List<ValueEmitter> arguments; private List<ValueEmitter> arguments;
@ -31,8 +33,10 @@ public class DynamicCallSite {
private List<RuntimeConstant> bootstrapArguments; private List<RuntimeConstant> bootstrapArguments;
private DependencyAgent agent; private DependencyAgent agent;
DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List<ValueEmitter> arguments, DynamicCallSite(MethodReference caller, MethodDescriptor calledMethod, ValueEmitter instance,
MethodHandle bootstrapMethod, List<RuntimeConstant> bootstrapArguments, DependencyAgent agent) { List<ValueEmitter> arguments, MethodHandle bootstrapMethod, List<RuntimeConstant> bootstrapArguments,
DependencyAgent agent) {
this.caller = caller;
this.calledMethod = calledMethod; this.calledMethod = calledMethod;
this.instance = instance; this.instance = instance;
this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments)); this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments));
@ -41,6 +45,10 @@ public class DynamicCallSite {
this.agent = agent; this.agent = agent;
} }
public MethodReference getCaller() {
return caller;
}
public MethodDescriptor getCalledMethod() { public MethodDescriptor getCalledMethod() {
return calledMethod; return calledMethod;
} }