From 5a8a0ac486c379fb1d434145ef3dd4c9509a9edb Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Mon, 13 Jan 2014 15:41:31 +0400 Subject: [PATCH] Lambda captured field remapper --- .../jet/codegen/asm/CapturedParamInfo.java | 10 +++ .../codegen/asm/ConstructorInvocation.java | 10 +++ .../jet/codegen/asm/InlineFieldRemapper.java | 63 +++++++++++++++++-- .../jet/codegen/asm/LambdaFieldRemapper.java | 25 ++++++++ .../jet/codegen/asm/LambdaTransformer.java | 9 ++- .../jet/codegen/asm/MethodInliner.java | 13 ++-- .../jetbrains/jet/codegen/asm/Parameters.java | 2 + 7 files changed, 116 insertions(+), 16 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/CapturedParamInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/CapturedParamInfo.java index d306f518bc4..462534f87d5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/CapturedParamInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/CapturedParamInfo.java @@ -26,6 +26,8 @@ public class CapturedParamInfo extends ParameterInfo { private int shift = 0; + private LambdaInfo recapturedFrom; + public static final CapturedParamInfo STUB = new CapturedParamInfo("", AsmTypeConstants.OBJECT_TYPE, true, -1, -1); public CapturedParamInfo(@NotNull String fieldName, @NotNull Type type, boolean skipped, int remapIndex, int index) { @@ -45,4 +47,12 @@ public class CapturedParamInfo extends ParameterInfo { public void setShift(int shift) { this.shift = shift; } + + public LambdaInfo getRecapturedFrom() { + return recapturedFrom; + } + + public void setRecapturedFrom(LambdaInfo recapturedFrom) { + this.recapturedFrom = recapturedFrom; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/ConstructorInvocation.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ConstructorInvocation.java index d275c9bd1e4..88b367586e5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/ConstructorInvocation.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ConstructorInvocation.java @@ -33,6 +33,8 @@ public class ConstructorInvocation { private List recaptured; + private Map recapturedLambdas; + ConstructorInvocation(String ownerInternalName, Map access) { this.ownerInternalName = ownerInternalName; this.access = access; @@ -74,4 +76,12 @@ public class ConstructorInvocation { public void setRecaptured(List recaptured) { this.recaptured = recaptured; } + + public Map getRecapturedLambdas() { + return recapturedLambdas; + } + + public void setRecapturedLambdas(Map recapturedLambdas) { + this.recapturedLambdas = recapturedLambdas; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineFieldRemapper.java index a5b8a4cadbb..b8706703b15 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineFieldRemapper.java @@ -16,30 +16,47 @@ package org.jetbrains.jet.codegen.asm; +import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.tree.AbstractInsnNode; import org.jetbrains.asm4.tree.FieldInsnNode; import org.jetbrains.asm4.tree.MethodNode; -import org.jetbrains.asm4.tree.VarInsnNode; + +import java.util.Collection; +import java.util.List; +import java.util.Map; import static org.jetbrains.jet.codegen.asm.MethodInliner.getPreviousNoLabelNoLine; public class InlineFieldRemapper extends LambdaFieldRemapper { - private String oldOwnerType; + private final String oldOwnerType; - private String newOwnerType; + private final String newOwnerType; - public InlineFieldRemapper(String oldOwnerType, String newOwnerType) { + private final Parameters parameters; + + private final Map recapturedLambdas; + + public InlineFieldRemapper(String oldOwnerType, String newOwnerType, Parameters parameters, Map recapturedLambdas) { this.oldOwnerType = oldOwnerType; this.newOwnerType = newOwnerType; + this.parameters = parameters; + this.recapturedLambdas = recapturedLambdas; } @Override public AbstractInsnNode doTransform( MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField ) { + boolean isRecaptured = isRecapruredLambdaType(fieldInsnNode.owner); + + if (!isRecaptured && capturedField.getLambda() != null) { + //strict inlining + return super.doTransform(node, fieldInsnNode, capturedField); + } + AbstractInsnNode prev = getPreviousNoLabelNoLine(fieldInsnNode); assert prev.getType() == AbstractInsnNode.VAR_INSN; @@ -56,8 +73,44 @@ public class InlineFieldRemapper extends LambdaFieldRemapper { node.instructions.remove(loadThis); fieldInsnNode.owner = newOwnerType; - fieldInsnNode.name = LambdaTransformer.getNewFieldName(fieldInsnNode.name); + fieldInsnNode.name = isRecaptured || capturedField.getRecapturedFrom() != null ? LambdaTransformer.getNewFieldName(capturedField.getFieldName()) : capturedField.getFieldName(); return fieldInsnNode; } + + @Override + public List markRecaptured(List originalCaptured, LambdaInfo lambda) { + List captured = parameters.getCaptured(); + for (CapturedParamInfo originalField : originalCaptured) { + for (CapturedParamInfo capturedParamInfo : captured) { + if (capturedParamInfo.getRecapturedFrom() == lambda) { + if (capturedParamInfo.getFieldName().equals(LambdaTransformer.getNewFieldName(originalField.getFieldName()))) { + originalField.setRecapturedFrom(lambda);//just mark recaptured + } + } + } + } + return originalCaptured; + } + + @Override + public boolean canProcess(String owner, String currentLambdaType) { + return super.canProcess(owner, currentLambdaType) || isRecapruredLambdaType(owner); + } + + private boolean isRecapruredLambdaType(String owner) { + return recapturedLambdas.containsKey(owner); + } + + + @Nullable + @Override + public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection captured) { + if (!isRecapruredLambdaType(fieldInsnNode.owner)) { + return super.findField(fieldInsnNode, captured); + } else { + LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner); + return super.findField(fieldInsnNode, info.getCapturedVars()); + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaFieldRemapper.java index 375946a293b..c2a2dab7c49 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaFieldRemapper.java @@ -16,12 +16,16 @@ package org.jetbrains.jet.codegen.asm; +import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.tree.AbstractInsnNode; import org.jetbrains.asm4.tree.FieldInsnNode; import org.jetbrains.asm4.tree.MethodNode; import org.jetbrains.asm4.tree.VarInsnNode; +import java.util.Collection; +import java.util.List; + import static org.jetbrains.jet.codegen.asm.MethodInliner.getPreviousNoLabelNoLine; public class LambdaFieldRemapper { @@ -43,4 +47,25 @@ public class LambdaFieldRemapper { return insn; } + public List markRecaptured(List originalCaptured, LambdaInfo lambda) { + return originalCaptured; + } + + + public boolean canProcess(String owner, String currentLambdaType) { + return owner.equals(currentLambdaType); + } + + @Nullable + public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection captured) { + String name = fieldInsnNode.name; + CapturedParamInfo result = null; + for (CapturedParamInfo valueDescriptor : captured) { + if (valueDescriptor.getFieldName().equals(name)) { + result = valueDescriptor; + break; + } + } + return result; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java index 57d033b094a..d6e1eadb4f7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java @@ -122,9 +122,10 @@ public class LambdaTransformer { Parameters parameters = getLambdaParameters(builder, invocation); MethodVisitor invokeVisitor = newMethod(classBuilder, invoke); + InlineFieldRemapper remapper = new InlineFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName(), parameters, invocation.getRecapturedLambdas()); MethodInliner inliner = new MethodInliner(invoke, parameters, info.subInline(info.nameGenerator.subGenerator("lambda")), oldLambdaType, - new LambdaFieldRemapper()); - inliner.doTransformAndMerge(invokeVisitor, new VarRemapper.ParamRemapper(parameters, null), new InlineFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName()), false); + remapper); + inliner.doTransformAndMerge(invokeVisitor, new VarRemapper.ParamRemapper(parameters, null), remapper, false); invokeVisitor.visitMaxs(-1, -1); generateConstructorAndFields(classBuilder, builder, invocation); @@ -212,16 +213,20 @@ public class LambdaTransformer { cur = cur.getNext(); } + Map recapturedLambdas = new HashMap(); //captured var of inlined parameter List recaptured = new ArrayList(); for (LambdaInfo info : additionalCaptured) { List vars = info.getCapturedVars(); for (CapturedParamInfo var : vars) { CapturedParamInfo recapturedParamInfo = builder.addCapturedParam(getNewFieldName(var.getFieldName()), var.getType(), true, var); + recapturedParamInfo.setRecapturedFrom(info); recaptured.add(var); } + recapturedLambdas.put(info.getLambdaClassType().getInternalName(), info); } invocation.setRecaptured(recaptured); + invocation.setRecapturedLambdas(recapturedLambdas); } @Nullable diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java index 27becc1529c..165eea3a9bf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java @@ -139,7 +139,7 @@ public class MethodInliner { List lambdaParameters = inlinableAccess.getParameters(); - Parameters params = new Parameters(lambdaParameters, Parameters.transformList(info.getCapturedVars(), lambdaParameters.size())); + Parameters params = new Parameters(lambdaParameters, Parameters.transformList(capturedRemapper.markRecaptured(info.getCapturedVars(), info), lambdaParameters.size())); MethodInliner inliner = new MethodInliner(info.getNode(), params, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), capturedRemapper); @@ -383,18 +383,13 @@ public class MethodInliner { FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; //TODO check closure String owner = fieldInsnNode.owner; - if (lambdaClassType.getInternalName().equals(fieldInsnNode.owner)) { + if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaClassType.getInternalName())) { String name = fieldInsnNode.name; String desc = fieldInsnNode.desc; Collection vars = paramsToSearch.getCaptured(); - CapturedParamInfo result = null; - for (CapturedParamInfo valueDescriptor : vars) { - if (valueDescriptor.getFieldName().equals(name)) { - result = valueDescriptor; - break; - } - } + CapturedParamInfo result = lambdaFieldRemapper.findField(fieldInsnNode, paramsToSearch.getCaptured()); + if (result == null) { throw new UnsupportedOperationException("Coudn't find field " + owner + diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/Parameters.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/Parameters.java index 2f0f18f8ca9..ced0380f823 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/Parameters.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/Parameters.java @@ -68,6 +68,7 @@ public class Parameters implements Iterable { capturedParamInfo.getIndex(), result.size() + realSize); newInfo.setLambda(capturedParamInfo.getLambda()); + newInfo.setRecapturedFrom(capturedParamInfo.getRecapturedFrom()); result.add(newInfo); @@ -84,6 +85,7 @@ public class Parameters implements Iterable { CapturedParamInfo newInfo = new CapturedParamInfo(capturedParamInfo.getFieldName(), capturedParamInfo.getType(), capturedParamInfo.isSkipped, capturedParamInfo.getRemapIndex(), result.size() + realSize); newInfo.setLambda(capturedParamInfo.getLambda()); + newInfo.setRecapturedFrom(capturedParamInfo.getRecapturedFrom()); result.add(newInfo); if (capturedParamInfo.getType().getSize() == 2) { result.add(CapturedParamInfo.STUB);