diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index b939ae6aa07..0b30649d307 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -221,4 +221,10 @@ public final class ClassFileFactory extends GenerationStateAware implements Outp this.sourceFiles = sourceFiles; } } + + public void removeInlinedClasses(Set classNamesToRemove) { + for (String classInternalName : classNamesToRemove) { + generators.remove(classInternalName + ".class"); + } + } } 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 5988e29c3dc..bb442e1b54b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -126,7 +126,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { try { node = createMethodNode(callableMethod); - inlineCall(node); + endCall(inlineCall(node)); } catch (CompilationException e) { throw e; @@ -141,7 +141,13 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { text, e, call.getCallElement()); } + + } + + private void endCall(@NotNull InlineResult result) { leaveTemps(); + + state.getFactory().removeInlinedClasses(result.getClassesToRemove()); } @NotNull @@ -191,7 +197,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { return node; } - private void inlineCall(MethodNode node) { + private InlineResult inlineCall(MethodNode node) { generateClosuresBodies(); List realParams = new ArrayList(actualParameters); @@ -205,16 +211,15 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator { InliningContext info = new InliningContext(expressionMap, null, null, null, state, codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), - codegen.getContext(), call, Collections.emptyMap()); + codegen.getContext(), call, Collections.emptyMap(), false); MethodInliner inliner = new MethodInliner(node, parameters, info, null, new LambdaFieldRemapper(), isSameModule); //with captured VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize); - inliner.doInline(codegen.v, remapper); + return inliner.doInline(codegen.v, remapper); } - private void generateClosuresBodies() { for (LambdaInfo info : expressionMap.values()) { info.setNode(generateLambdaBody(info)); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java new file mode 100644 index 00000000000..f2a73522043 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.inline; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class InlineResult { + + private final Set classesToRemove = new HashSet(); + + private InlineResult() { + + } + + @NotNull + public static InlineResult create() { + return new InlineResult(); + } + + @NotNull + public InlineResult addAllClassesToRemove(@NotNull InlineResult child) { + classesToRemove.addAll(child.classesToRemove); + return this; + } + + public void addClassToRemove(@NotNull String classInternalName) { + classesToRemove.add(classInternalName); + } + + @NotNull + public Set getClassesToRemove() { + return classesToRemove; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java index dcf857ac714..9881497530a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java @@ -27,7 +27,7 @@ import java.util.Map; public class InliningContext { - public final Map expresssionMap; + public final Map expressionMap; public final List invokeCalls; @@ -45,6 +45,8 @@ public class InliningContext { public final Map typeMapping; + public final boolean isInliningLambda; + public InliningContext( Map map, List accesses, @@ -54,9 +56,10 @@ public class InliningContext { NameGenerator nameGenerator, CodegenContext startContext, Call call, - Map typeMapping + Map typeMapping, + boolean isInliningLambda ) { - expresssionMap = map; + expressionMap = map; invokeCalls = accesses; constructorInvocation = invocation; this.remapper = remapper; @@ -65,16 +68,26 @@ public class InliningContext { this.startContext = startContext; this.call = call; this.typeMapping = typeMapping; + this.isInliningLambda = isInliningLambda; } public InliningContext subInline(NameGenerator generator) { return subInline(generator, Collections.emptyMap()); } - public InliningContext subInline(NameGenerator generator, Map additionalTypeMappings) { - HashMap newTypeMappings = new HashMap(typeMapping); - newTypeMappings.putAll(additionalTypeMappings); - return new InliningContext(expresssionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call, - newTypeMappings); + public InliningContext subInlineLambda(NameGenerator generator) { + return subInline(generator, Collections.emptyMap(), true); } + + public InliningContext subInline(NameGenerator generator, Map additionalTypeMappings) { + return subInline(generator, additionalTypeMappings, isInliningLambda); + } + + public InliningContext subInline(NameGenerator generator, Map additionalTypeMappings, boolean isInliningLambda) { + Map newTypeMappings = new HashMap(typeMapping); + newTypeMappings.putAll(additionalTypeMappings); + return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call, + newTypeMappings, isInliningLambda); + } + } 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 f224e29a4c1..62aabbe90f8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/LambdaTransformer.java @@ -108,7 +108,7 @@ public class LambdaTransformer { } } - public void doTransform(ConstructorInvocation invocation) { + public InlineResult doTransform(ConstructorInvocation invocation) { ClassBuilder classBuilder = createClassBuilder(); //TODO: public visibility for inline function @@ -128,7 +128,7 @@ public class LambdaTransformer { remapper = new RegeneratedLambdaFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName(), parameters, invocation.getCapturedLambdasToInline()); MethodInliner inliner = new MethodInliner(invoke, parameters, info.subInline(info.nameGenerator.subGenerator("lambda")), oldLambdaType, remapper, isSameModule); - 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); generateConstructorAndFields(classBuilder, builder, invocation); @@ -150,6 +150,7 @@ public class LambdaTransformer { classBuilder.done(); invocation.setNewLambdaType(newLambdaType); + return result; } private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder builder, @NotNull ConstructorInvocation invocation) { 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 baa73e000e1..36054d846ab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -46,6 +46,8 @@ public class MethodInliner { //current state private final Map currentTypeMapping = new HashMap(); + private final InlineResult result; + /* * * @param node @@ -68,14 +70,15 @@ public class MethodInliner { this.lambdaFieldRemapper = lambdaFieldRemapper; this.isSameModule = isSameModule; this.typeMapper = parent.state.getTypeMapper(); + this.result = InlineResult.create(); } - public void doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) { - doInline(adapter, remapper, new LambdaFieldRemapper(), true); + public InlineResult doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) { + return doInline(adapter, remapper, new LambdaFieldRemapper(), true); } - public void doInline( + public InlineResult doInline( MethodVisitor adapter, VarRemapper.ParamRemapper remapper, LambdaFieldRemapper capturedRemapper, boolean remapReturn @@ -98,6 +101,7 @@ public class MethodInliner { transformedNode.accept(visitor); visitor.visitLabel(end); + return result; } private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) { @@ -128,6 +132,11 @@ public class MethodInliner { isSameModule, newLambdaType); transformer.doTransform(invocation); + + if (parent.isInliningLambda) { + //this class is transformed and original not used so we should remove original one after inlining + result.addClassToRemove(invocation.getOwnerInternalName()); + } } } @@ -154,11 +163,14 @@ public class MethodInliner { Parameters lambdaParameters = info.addAllParameters(capturedRemapper); setInlining(true); - MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), - capturedRemapper, true /*cause all calls in same module as lambda*/); + MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInlineLambda( + parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), + capturedRemapper, true /*cause all calls in same module as lambda*/ + ); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift); - inliner.doInline(this.mv, remapper); //TODO add skipped this and receiver + InlineResult lambdaResult = inliner.doInline(this.mv, remapper);//TODO add skipped this and receiver + result.addAllClassesToRemove(lambdaResult); //return value boxing/unboxing Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();