diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/FieldRemapper.java similarity index 88% rename from compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java rename to compiler/backend/src/org/jetbrains/jet/codegen/inline/FieldRemapper.java index 9c69db1a338..66bfb4e1721 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/FieldRemapper.java @@ -27,15 +27,15 @@ import org.jetbrains.jet.codegen.StackValue; import java.util.Collection; import java.util.List; -public class LambdaFieldRemapper { +public class FieldRemapper { private final String lambdaInternalName; - protected LambdaFieldRemapper parent; + protected FieldRemapper parent; private final Parameters params; - public LambdaFieldRemapper(@Nullable String lambdaInternalName, @Nullable LambdaFieldRemapper parent, @NotNull Parameters methodParams) { + public FieldRemapper(@Nullable String lambdaInternalName, @Nullable FieldRemapper parent, @NotNull Parameters methodParams) { this.lambdaInternalName = lambdaInternalName; this.parent = parent; params = methodParams; @@ -51,9 +51,9 @@ public class LambdaFieldRemapper { return fieldOwner.equals(getLambdaInternalName()); } + @Nullable public AbstractInsnNode transformIfNeeded( @NotNull List capturedFieldAccess, - int currentInstruction, @NotNull MethodNode node ) { if (capturedFieldAccess.size() == 1) { @@ -61,6 +61,15 @@ public class LambdaFieldRemapper { return null; } + return transformIfNeeded(capturedFieldAccess, 1, node); + } + + @Nullable + private AbstractInsnNode transformIfNeeded( + @NotNull List capturedFieldAccess, + int currentInstruction, + @NotNull MethodNode node + ) { AbstractInsnNode transformed = null; boolean checkParent = !isRoot() && currentInstruction < capturedFieldAccess.size() - 1; if (checkParent) { @@ -99,7 +108,7 @@ public class LambdaFieldRemapper { return null; } - public LambdaFieldRemapper getParent() { + public FieldRemapper getParent() { return parent; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index 1d4fc21f218..3bacb255089 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -213,11 +213,11 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), codegen.getContext(), call, Collections.emptyMap(), false, false); - MethodInliner inliner = new MethodInliner(node, parameters, info, new LambdaFieldRemapper(null, null, parameters), isSameModule, "InlineCodegenRoot " + call.getCallElement()); //with captured + MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "InlineCodegenRoot " + call.getCallElement()); //with captured VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize); - return inliner.doInline(codegen.v, remapper, new LambdaFieldRemapper(null, null, parameters)); + return inliner.doInline(codegen.v, remapper, new FieldRemapper(null, null, parameters)); } private void generateClosuresBodies() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinedLambdaRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinedLambdaRemapper.java index 54dbec68898..8e5edee9b1e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinedLambdaRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlinedLambdaRemapper.java @@ -22,11 +22,11 @@ import org.jetbrains.asm4.tree.FieldInsnNode; import java.util.Collection; -public class InlinedLambdaRemapper extends LambdaFieldRemapper { +public class InlinedLambdaRemapper extends FieldRemapper { public InlinedLambdaRemapper( @NotNull String lambdaInternalName, - @NotNull LambdaFieldRemapper parent, + @NotNull FieldRemapper parent, @NotNull Parameters methodParams ) { super(lambdaInternalName, parent, methodParams); @@ -51,7 +51,7 @@ public class InlinedLambdaRemapper extends LambdaFieldRemapper { } @Override - public LambdaFieldRemapper getParent() { + public FieldRemapper getParent() { return parent.getParent(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java index f8d00cc72be..d478e687fd4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaInfo.java @@ -138,7 +138,7 @@ public class LambdaInfo implements CapturedParamOwner { return Arrays.asList(types); } - public Parameters addAllParameters(@NotNull LambdaFieldRemapper remapper) { + public Parameters addAllParameters(@NotNull FieldRemapper remapper) { ParametersBuilder builder = ParametersBuilder.newBuilder(); //add skipped this cause inlined lambda doesn't have it builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java index 28c646edc7f..91d19712bf0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java @@ -105,7 +105,7 @@ public class LambdaTransformer { } } - public InlineResult doTransform(ConstructorInvocation invocation, LambdaFieldRemapper parentRemapper) { + public InlineResult doTransform(ConstructorInvocation invocation, FieldRemapper parentRemapper) { ClassBuilder classBuilder = createClassBuilder(); //TODO: public visibility for inline function diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index 00639cd75d5..bf93e1771a4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -15,7 +15,6 @@ import org.jetbrains.asm4.tree.analysis.*; import org.jetbrains.jet.codegen.ClosureCodegen; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.state.JetTypeMapper; -import org.jetbrains.jet.utils.UtilsPackage; import java.util.*; @@ -30,7 +29,7 @@ public class MethodInliner { private final InliningContext inliningContext; - private final LambdaFieldRemapper nodeRemapper; + private final FieldRemapper nodeRemapper; private final boolean isSameModule; @@ -58,7 +57,7 @@ public class MethodInliner { @NotNull MethodNode node, @NotNull Parameters parameters, @NotNull InliningContext parent, - @NotNull LambdaFieldRemapper nodeRemapper, + @NotNull FieldRemapper nodeRemapper, boolean isSameModule, @NotNull String errorPrefix ) { @@ -73,14 +72,14 @@ public class MethodInliner { } - public InlineResult doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper, LambdaFieldRemapper fieldRemapper) { - return doInline(adapter, remapper, fieldRemapper, true); + public InlineResult doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper, FieldRemapper capturedRemapper) { + return doInline(adapter, remapper, capturedRemapper, true); } public InlineResult doInline( MethodVisitor adapter, VarRemapper.ParamRemapper remapper, - LambdaFieldRemapper capturedRemapper, boolean remapReturn + FieldRemapper capturedRemapper, boolean remapReturn ) { //analyze body MethodNode transformedNode = markPlacesForInlineAndRemoveInlinable(node); @@ -93,20 +92,17 @@ public class MethodInliner { RemapVisitor visitor = new RemapVisitor(adapter, end, remapper, remapReturn, nodeRemapper); try { transformedNode.accept(visitor); - } catch (Exception e) { - String text = InlineCodegen.getNodeText(transformedNode); - - throw new RuntimeException(errorPrefix + ": couldn't inline method call '" + - transformedNode + - "\ncause: " + - text, e); + } + catch (Exception e) { + throw new RuntimeException(errorPrefix + ": couldn't inline method call " + transformedNode + "\ncause: " + + InlineCodegen.getNodeText(transformedNode), e); } visitor.visitLabel(end); return result; } - private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) { + private MethodNode doInline(MethodNode node, final FieldRemapper capturedRemapper) { final Deque currentInvokes = new LinkedList(invokeCalls); @@ -168,13 +164,13 @@ public class MethodInliner { InlinedLambdaRemapper newCapturedRemapper = new InlinedLambdaRemapper(info.getLambdaClassType().getInternalName(), capturedRemapper, lambdaParameters); - LambdaFieldRemapper lambdaFieldRemapper = - new LambdaFieldRemapper(info.getLambdaClassType().getInternalName(), capturedRemapper, lambdaParameters); + FieldRemapper fieldRemapper = + new FieldRemapper(info.getLambdaClassType().getInternalName(), capturedRemapper, lambdaParameters); setInlining(true); MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, inliningContext.subInlineLambda(info), - lambdaFieldRemapper, true /*cause all calls in same module as lambda*/, + fieldRemapper, true /*cause all calls in same module as lambda*/, "Lambda inlining " + info.getLambdaClassType().getInternalName()); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift); @@ -212,12 +208,9 @@ public class MethodInliner { return resultNode; } - public CapturedParamInfo findCapturedField(FieldInsnNode node) { - return findCapturedField(node, nodeRemapper); - } - @NotNull - public static CapturedParamInfo findCapturedField(FieldInsnNode node, LambdaFieldRemapper fieldRemapper) { + public static CapturedParamInfo findCapturedField(FieldInsnNode node, FieldRemapper fieldRemapper) { + assert node.name.startsWith("$$$") : "Captured field template should start with $$$ prefix"; FieldInsnNode fin = new FieldInsnNode(node.getOpcode(), node.owner, node.name.substring(3), node.desc); CapturedParamInfo field = fieldRemapper.findField(fin); if (field == null) { @@ -282,13 +275,10 @@ public class MethodInliner { Frame[] sources; try { sources = analyzer.analyze("fake", node); - } catch (AnalyzerException e) { - String text = InlineCodegen.getNodeText(node); - - throw new RuntimeException("Couldn't inline method call '" + - node + - "\ncause: " + - text, e); + } + catch (AnalyzerException e) { + throw new RuntimeException("Couldn't inline method call " + node + "\ncause: " + + InlineCodegen.getNodeText(node), e); } AbstractInsnNode cur = node.instructions.getFirst(); @@ -378,12 +368,11 @@ public class MethodInliner { if (varIndex < parameters.totalSize()) { return parameters.get(varIndex).getLambda(); } - } else if (insnNode instanceof FieldInsnNode) { + } + else if (insnNode instanceof FieldInsnNode) { FieldInsnNode fieldInsnNode = (FieldInsnNode) insnNode; if (fieldInsnNode.name.startsWith("$$$")) { - CapturedParamInfo field = findCapturedField(fieldInsnNode); - return field.getLambda(); - + return findCapturedField(fieldInsnNode, nodeRemapper).getLambda(); } } @@ -418,13 +407,14 @@ public class MethodInliner { return; } - //encode all captured variable chains - ALOAD 0 ALOAD this$0 GETFIELD $captured - to GETFIELD $$$$captured + //Fold all captured variable chain - ALOAD 0 ALOAD this$0 GETFIELD $captured - to GETFIELD $$$$captured + //On future decoding this field could be inline or unfolded in another field access chain (it can differ in some missed this$0) AbstractInsnNode cur = node.instructions.getFirst(); while (cur != null) { if (cur instanceof VarInsnNode && cur.getOpcode() == Opcodes.ALOAD) { if (((VarInsnNode) cur).var == 0) { List accessChain = getCapturedFieldAccessChain((VarInsnNode) cur); - AbstractInsnNode insnNode = nodeRemapper.transformIfNeeded(accessChain, 1, node); + AbstractInsnNode insnNode = nodeRemapper.transformIfNeeded(accessChain, node); if (insnNode != null) { cur = insnNode; } @@ -435,15 +425,16 @@ public class MethodInliner { } @NotNull - public static List getCapturedFieldAccessChain(@NotNull VarInsnNode node) { + public static List getCapturedFieldAccessChain(@NotNull VarInsnNode aload0) { List fieldAccessChain = new ArrayList(); - fieldAccessChain.add(node); - AbstractInsnNode next = node.getNext(); + fieldAccessChain.add(aload0); + AbstractInsnNode next = aload0.getNext(); while (next != null && next instanceof FieldInsnNode) { fieldAccessChain.add(next); - if("this$0".equals(((FieldInsnNode) next).name)) { + if ("this$0".equals(((FieldInsnNode) next).name)) { next = next.getNext(); - } else { + } + else { break; } } @@ -451,14 +442,6 @@ public class MethodInliner { return fieldAccessChain; } - public static AbstractInsnNode getPreviousNoLabelNoLine(AbstractInsnNode cur) { - AbstractInsnNode prev = cur.getPrevious(); - while (prev.getType() == AbstractInsnNode.LABEL || prev.getType() == AbstractInsnNode.LINE) { - prev = prev.getPrevious(); - } - return prev; - } - public static void putStackValuesIntoLocals(List directOrder, int shift, InstructionAdapter iv, String descriptor) { Type[] actualParams = Type.getArgumentTypes(descriptor); assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!"; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegeneratedLambdaFieldRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegeneratedLambdaFieldRemapper.java index fa800bc95c5..efcaeb62366 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegeneratedLambdaFieldRemapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegeneratedLambdaFieldRemapper.java @@ -27,7 +27,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; -public class RegeneratedLambdaFieldRemapper extends LambdaFieldRemapper { +public class RegeneratedLambdaFieldRemapper extends FieldRemapper { private final String oldOwnerType; @@ -42,7 +42,7 @@ public class RegeneratedLambdaFieldRemapper extends LambdaFieldRemapper { String newOwnerType, Parameters parameters, Map recapturedLambdas, - LambdaFieldRemapper remapper + FieldRemapper remapper ) { super(oldOwnerType, remapper, parameters); this.oldOwnerType = oldOwnerType; @@ -70,7 +70,7 @@ public class RegeneratedLambdaFieldRemapper extends LambdaFieldRemapper { throw new IllegalStateException("Captured parameter should exists in outer context: " + originalField.getFieldName()); } - CapturedParamInfo info = builder.addCapturedParam(foundField, foundField); + builder.addCapturedParam(foundField, foundField); } } else { //in case when inlining lambda into another one inside inline function @@ -116,6 +116,7 @@ public class RegeneratedLambdaFieldRemapper extends LambdaFieldRemapper { @Nullable @Override public StackValue getFieldForInline(@NotNull FieldInsnNode node, @Nullable StackValue prefix) { + assert node.name.startsWith("$$$") : "Captured field template should start with $$$ prefix"; FieldInsnNode fin = new FieldInsnNode(node.getOpcode(), node.owner, node.name.substring(3), node.desc); CapturedParamInfo field = findFieldInMyCaptured(fin); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemapVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemapVisitor.java index 8b354a0b9b7..f556da2431c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemapVisitor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemapVisitor.java @@ -31,9 +31,9 @@ public class RemapVisitor extends InstructionAdapter { private final VarRemapper remapper; private final boolean remapReturn; - private LambdaFieldRemapper nodeRemapper; + private FieldRemapper nodeRemapper; - protected RemapVisitor(MethodVisitor mv, Label end, VarRemapper.ParamRemapper remapper, boolean remapReturn, LambdaFieldRemapper nodeRemapper) { + protected RemapVisitor(MethodVisitor mv, Label end, VarRemapper.ParamRemapper remapper, boolean remapReturn, FieldRemapper nodeRemapper) { super(InlineCodegenUtil.API, mv); this.end = end; this.remapper = remapper; @@ -67,8 +67,10 @@ public class RemapVisitor extends InstructionAdapter { if (nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot()) { FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc); StackValue inline = nodeRemapper.getFieldForInline(fin, null); + assert inline != null : "Captured field should have not null stackValue " + fin; inline.put(inline.type, this); - } else { + } + else { super.visitFieldInsn(opcode, owner, name, desc); } }