Support nested chain of non-inline lambdas inside inline one

This commit is contained in:
Mikhael Bogdanov
2014-03-05 16:42:47 +04:00
parent 4937812414
commit 632061b324
5 changed files with 74 additions and 24 deletions
@@ -37,10 +37,18 @@ public class ConstructorInvocation {
private Map<String, LambdaInfo> capturedLambdasToInline; private Map<String, LambdaInfo> capturedLambdasToInline;
ConstructorInvocation(String ownerInternalName, Map<Integer, LambdaInfo> lambdasToInline, boolean isSameModule) { private boolean capturedOuterRegenerated;
ConstructorInvocation(
String ownerInternalName,
Map<Integer, LambdaInfo> lambdasToInline,
boolean isSameModule,
boolean capturedOuterRegenerated
) {
this.ownerInternalName = ownerInternalName; this.ownerInternalName = ownerInternalName;
this.lambdasToInline = lambdasToInline; this.lambdasToInline = lambdasToInline;
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
this.capturedOuterRegenerated = capturedOuterRegenerated;
} }
public String getOwnerInternalName() { public String getOwnerInternalName() {
@@ -48,7 +56,7 @@ public class ConstructorInvocation {
} }
public boolean shouldRegenerate() { public boolean shouldRegenerate() {
return !lambdasToInline.isEmpty() || !isSameModule; return !lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated;
} }
public Map<Integer, LambdaInfo> getLambdasToInline() { public Map<Integer, LambdaInfo> getLambdasToInline() {
@@ -86,4 +94,5 @@ public class ConstructorInvocation {
public void setCapturedLambdasToInline(Map<String, LambdaInfo> capturedLambdasToInline) { public void setCapturedLambdasToInline(Map<String, LambdaInfo> capturedLambdasToInline) {
this.capturedLambdasToInline = capturedLambdasToInline; this.capturedLambdasToInline = capturedLambdasToInline;
} }
} }
@@ -211,7 +211,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
InliningContext info = InliningContext info =
new InliningContext(expressionMap, null, null, null, state, new InliningContext(expressionMap, null, null, null, state,
codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()),
codegen.getContext(), call, Collections.<String, String>emptyMap(), false); codegen.getContext(), call, Collections.<String, String>emptyMap(), false, false);
MethodInliner inliner = new MethodInliner(node, parameters, info, null, new LambdaFieldRemapper(), isSameModule); //with captured MethodInliner inliner = new MethodInliner(node, parameters, info, null, new LambdaFieldRemapper(), isSameModule); //with captured
@@ -47,6 +47,8 @@ public class InliningContext {
public final boolean isInliningLambda; public final boolean isInliningLambda;
public final boolean classRegeneration;
public InliningContext( public InliningContext(
Map<Integer, LambdaInfo> map, Map<Integer, LambdaInfo> map,
List<InvokeCall> accesses, List<InvokeCall> accesses,
@@ -57,7 +59,8 @@ public class InliningContext {
CodegenContext startContext, CodegenContext startContext,
Call call, Call call,
Map<String, String> typeMapping, Map<String, String> typeMapping,
boolean isInliningLambda boolean isInliningLambda,
boolean classRegeneration
) { ) {
expressionMap = map; expressionMap = map;
invokeCalls = accesses; invokeCalls = accesses;
@@ -69,14 +72,17 @@ public class InliningContext {
this.call = call; this.call = call;
this.typeMapping = typeMapping; this.typeMapping = typeMapping;
this.isInliningLambda = isInliningLambda; this.isInliningLambda = isInliningLambda;
this.classRegeneration = classRegeneration;
} }
public InliningContext subInline(NameGenerator generator) { public InliningContext subInline(NameGenerator generator) {
return subInline(generator, Collections.<String, String>emptyMap()); return subInline(generator, Collections.<String, String>emptyMap());
} }
public InliningContext subInlineLambda(NameGenerator generator) { public InliningContext subInlineLambda(LambdaInfo lambdaInfo) {
return subInline(generator, Collections.<String, String>emptyMap(), true); Map<String, String> map = new HashMap();
map.put(lambdaInfo.getLambdaClassType().getInternalName(), null); //mark lambda inlined
return subInline(nameGenerator.subGenerator("lambda"), map, true);
} }
public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) { public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
@@ -87,7 +93,11 @@ public class InliningContext {
Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping); Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
newTypeMappings.putAll(additionalTypeMappings); newTypeMappings.putAll(additionalTypeMappings);
return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call, return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call,
newTypeMappings, isInliningLambda); newTypeMappings, isInliningLambda, classRegeneration);
} }
public InliningContext classRegeneration() {
return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, nameGenerator, startContext, call,
typeMapping, isInliningLambda, true);
}
} }
@@ -55,7 +55,7 @@ public class LambdaTransformer {
private final MethodNode bridge; private final MethodNode bridge;
private final InliningContext info; private final InliningContext inliningContext;
private final Type oldLambdaType; private final Type oldLambdaType;
@@ -67,11 +67,11 @@ public class LambdaTransformer {
private String[] interfaces; private String[] interfaces;
private final boolean isSameModule; private final boolean isSameModule;
public LambdaTransformer(String lambdaInternalName, InliningContext info, boolean isSameModule, Type newLambdaType) { public LambdaTransformer(String lambdaInternalName, InliningContext inliningContext, boolean isSameModule, Type newLambdaType) {
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
this.state = info.state; this.state = inliningContext.state;
this.typeMapper = state.getTypeMapper(); this.typeMapper = state.getTypeMapper();
this.info = info; this.inliningContext = inliningContext;
this.oldLambdaType = Type.getObjectType(lambdaInternalName); this.oldLambdaType = Type.getObjectType(lambdaInternalName);
this.newLambdaType = newLambdaType; this.newLambdaType = newLambdaType;
@@ -130,7 +130,7 @@ public class LambdaTransformer {
MethodVisitor invokeVisitor = newMethod(classBuilder, invoke); MethodVisitor invokeVisitor = newMethod(classBuilder, invoke);
RegeneratedLambdaFieldRemapper RegeneratedLambdaFieldRemapper
remapper = new RegeneratedLambdaFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName(), parameters, invocation.getCapturedLambdasToInline()); remapper = new RegeneratedLambdaFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName(), parameters, invocation.getCapturedLambdasToInline());
MethodInliner inliner = new MethodInliner(invoke, parameters, info.subInline(info.nameGenerator.subGenerator("lambda")), oldLambdaType, MethodInliner inliner = new MethodInliner(invoke, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), oldLambdaType,
remapper, isSameModule); remapper, isSameModule);
InlineResult result = inliner.doInline(invokeVisitor, new VarRemapper.ParamRemapper(parameters, 0), remapper, false); InlineResult result = inliner.doInline(invokeVisitor, new VarRemapper.ParamRemapper(parameters, 0), remapper, false);
invokeVisitor.visitMaxs(-1, -1); invokeVisitor.visitMaxs(-1, -1);
@@ -182,8 +182,8 @@ public class LambdaTransformer {
} }
private ClassBuilder createClassBuilder() { private ClassBuilder createClassBuilder() {
return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, info.call.getCallElement().getContainingFile()), return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, inliningContext.call.getCallElement().getContainingFile()),
new TypeRemapper(info.typeMapping)); new TypeRemapper(inliningContext.typeMapping));
} }
private static MethodVisitor newMethod(ClassBuilder builder, MethodNode original) { private static MethodVisitor newMethod(ClassBuilder builder, MethodNode original) {
@@ -13,6 +13,7 @@ import org.jetbrains.asm4.commons.Method;
import org.jetbrains.asm4.commons.RemappingMethodAdapter; import org.jetbrains.asm4.commons.RemappingMethodAdapter;
import org.jetbrains.asm4.tree.*; import org.jetbrains.asm4.tree.*;
import org.jetbrains.asm4.tree.analysis.*; import org.jetbrains.asm4.tree.analysis.*;
import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.jet.codegen.ClosureCodegen; import org.jetbrains.jet.codegen.ClosureCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
@@ -28,7 +29,7 @@ public class MethodInliner {
private final Parameters parameters; private final Parameters parameters;
private final InliningContext parent; private final InliningContext inliningContext;
@Nullable @Nullable
private final Type lambdaType; private final Type lambdaType;
@@ -52,7 +53,7 @@ public class MethodInliner {
* *
* @param node * @param node
* @param parameters * @param parameters
* @param parent * @param inliningContext
* @param lambdaType - in case on lambda 'invoke' inlining * @param lambdaType - in case on lambda 'invoke' inlining
*/ */
public MethodInliner( public MethodInliner(
@@ -65,7 +66,7 @@ public class MethodInliner {
) { ) {
this.node = node; this.node = node;
this.parameters = parameters; this.parameters = parameters;
this.parent = parent; this.inliningContext = parent;
this.lambdaType = lambdaType; this.lambdaType = lambdaType;
this.lambdaFieldRemapper = lambdaFieldRemapper; this.lambdaFieldRemapper = lambdaFieldRemapper;
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
@@ -125,15 +126,16 @@ public class MethodInliner {
if (invocation.shouldRegenerate()) { if (invocation.shouldRegenerate()) {
//TODO: need poping of type but what to do with local funs??? //TODO: need poping of type but what to do with local funs???
Type newLambdaType = Type.getObjectType(parent.nameGenerator.genLambdaClassName()); Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName());
currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName()); currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName());
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(), LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(),
parent.subInline(parent.nameGenerator, currentTypeMapping), inliningContext.subInline(inliningContext.nameGenerator, currentTypeMapping).classRegeneration(),
isSameModule, newLambdaType); isSameModule, newLambdaType);
transformer.doTransform(invocation); InlineResult transformResult = transformer.doTransform(invocation);
result.addAllClassesToRemove(transformResult);
if (parent.isInliningLambda) { if (inliningContext.isInliningLambda) {
//this class is transformed and original not used so we should remove original one after inlining //this class is transformed and original not used so we should remove original one after inlining
result.addClassToRemove(invocation.getOwnerInternalName()); result.addClassToRemove(invocation.getOwnerInternalName());
} }
@@ -163,8 +165,9 @@ public class MethodInliner {
Parameters lambdaParameters = info.addAllParameters(capturedRemapper); Parameters lambdaParameters = info.addAllParameters(capturedRemapper);
setInlining(true); setInlining(true);
MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInlineLambda( MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters,
parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), inliningContext.subInlineLambda(info),
info.getLambdaClassType(),
capturedRemapper, true /*cause all calls in same module as lambda*/ capturedRemapper, true /*cause all calls in same module as lambda*/
); );
@@ -331,7 +334,7 @@ public class MethodInliner {
} }
} }
constructorInvocations.add(new ConstructorInvocation(owner, lambdaMapping, isSameModule)); constructorInvocations.add(new ConstructorInvocation(owner, lambdaMapping, isSameModule, inliningContext.classRegeneration));
} }
} }
} }
@@ -423,6 +426,34 @@ public class MethodInliner {
} else { } else {
cur = this.lambdaFieldRemapper.doTransform(node, fieldInsnNode, result); cur = this.lambdaFieldRemapper.doTransform(node, fieldInsnNode, result);
} }
} else {
Type type1 = Type.getType(fieldInsnNode.desc);
if (!AsmUtil.isPrimitive(type1)) {
String type = type1.getInternalName();
if (inliningContext.typeMapping.containsKey(type)) {
//TODO value could be null
String newTypeOrSkip = inliningContext.typeMapping.get(type);
if (newTypeOrSkip != null) {
fieldInsnNode.owner = newTypeOrSkip;
}
else {
//generate owner of next instruction
AbstractInsnNode previous = fieldInsnNode.getPrevious();
AbstractInsnNode nextInstruction = fieldInsnNode.getNext();
if (!(nextInstruction instanceof FieldInsnNode)) {
throw new IllegalStateException(
"Instruction after inlined one should be field access: " + nextInstruction);
}
if (!(previous instanceof FieldInsnNode)) {
throw new IllegalStateException("Instruction before inlined one should be field access: " + previous);
}
cur = nextInstruction;
node.instructions.remove(cur.getPrevious());
((FieldInsnNode) cur).owner = Type.getType(((FieldInsnNode) previous).desc).getInternalName();
((FieldInsnNode) cur).name = LambdaTransformer.getNewFieldName(((FieldInsnNode) cur).name);
}
}
}
} }
} }
cur = cur.getNext(); cur = cur.getNext();