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;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.teavm.cache.NoCache;
import org.teavm.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DynamicCallSite;
@ -29,6 +31,7 @@ import org.teavm.model.FieldHolder;
import org.teavm.model.MethodHandle;
import org.teavm.model.MethodHolder;
import org.teavm.model.PrimitiveType;
import org.teavm.model.TextLocation;
import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
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_MARKERS = 2;
private static final int FLAG_BRIDGES = 4;
private int lambdaIndex;
private Map<String, Integer> lambdaIdsByMethod = new HashMap<>();
@Override
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) {
@ -50,7 +53,11 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
ClassReaderSource classSource = callSite.getAgent().getClassSource();
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);
if (samClass != null && samClass.hasModifier(ElementModifier.INTERFACE)) {
implementor.setParent("java.lang.Object");
@ -61,15 +68,16 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
int capturedVarCount = callSite.getCalledMethod().parameterCount();
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()));
createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType,
samMethodType);
samMethodType, callerPe.getCurrentLocation());
MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType);
worker.getAnnotations().add(new AnnotationHolder(NoCache.class.getName()));
worker.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(worker, callSite.getAgent().getClassSource());
pe.setCurrentLocation(callerPe.getCurrentLocation());
ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1];
for (int i = 0; i < arguments.length; ++i) {
@ -119,7 +127,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
for (int i = 0; i < bridgeCount; ++i) {
ValueType[] bridgeType = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getMethodType();
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);
signature[types.length] = ValueType.VOID;
MethodHolder ctor = new MethodHolder("<init>", signature);
ctor.setLevel(AccessLevel.PUBLIC);
ProgramEmitter pe = ProgramEmitter.create(ctor, classSource);
pe.setCurrentLocation(location);
ValueEmitter thisVar = pe.var(0, implementor);
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,
ValueType[] bridgeTypes) {
ValueType[] bridgeTypes, TextLocation location) {
if (Arrays.equals(types, bridgeTypes)) {
return;
}
@ -293,6 +303,7 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
bridge.setLevel(AccessLevel.PUBLIC);
bridge.getModifiers().add(ElementModifier.BRIDGE);
ProgramEmitter pe = ProgramEmitter.create(bridge, classSource);
pe.setCurrentLocation(location);
ValueEmitter thisVar = pe.var(0, implementor);
ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1];
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());
});
}

View File

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

View File

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

View File

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

View File

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