Don't generated redundant class files

This commit is contained in:
Mikhael Bogdanov
2014-03-05 14:00:22 +04:00
parent ea5788f86c
commit 00764d0ae1
6 changed files with 109 additions and 21 deletions
@@ -221,4 +221,10 @@ public final class ClassFileFactory extends GenerationStateAware implements Outp
this.sourceFiles = sourceFiles; this.sourceFiles = sourceFiles;
} }
} }
public void removeInlinedClasses(Set<String> classNamesToRemove) {
for (String classInternalName : classNamesToRemove) {
generators.remove(classInternalName + ".class");
}
}
} }
@@ -126,7 +126,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
try { try {
node = createMethodNode(callableMethod); node = createMethodNode(callableMethod);
inlineCall(node); endCall(inlineCall(node));
} }
catch (CompilationException e) { catch (CompilationException e) {
throw e; throw e;
@@ -141,7 +141,13 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
text, e, call.getCallElement()); text, e, call.getCallElement());
} }
}
private void endCall(@NotNull InlineResult result) {
leaveTemps(); leaveTemps();
state.getFactory().removeInlinedClasses(result.getClassesToRemove());
} }
@NotNull @NotNull
@@ -191,7 +197,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
return node; return node;
} }
private void inlineCall(MethodNode node) { private InlineResult inlineCall(MethodNode node) {
generateClosuresBodies(); generateClosuresBodies();
List<ParameterInfo> realParams = new ArrayList<ParameterInfo>(actualParameters); List<ParameterInfo> realParams = new ArrayList<ParameterInfo>(actualParameters);
@@ -205,16 +211,15 @@ 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()); codegen.getContext(), call, Collections.<String, String>emptyMap(), 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
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize);
inliner.doInline(codegen.v, remapper); return inliner.doInline(codegen.v, remapper);
} }
private void generateClosuresBodies() { private void generateClosuresBodies() {
for (LambdaInfo info : expressionMap.values()) { for (LambdaInfo info : expressionMap.values()) {
info.setNode(generateLambdaBody(info)); info.setNode(generateLambdaBody(info));
@@ -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<String> classesToRemove = new HashSet<String>();
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<String> getClassesToRemove() {
return classesToRemove;
}
}
@@ -27,7 +27,7 @@ import java.util.Map;
public class InliningContext { public class InliningContext {
public final Map<Integer, LambdaInfo> expresssionMap; public final Map<Integer, LambdaInfo> expressionMap;
public final List<InvokeCall> invokeCalls; public final List<InvokeCall> invokeCalls;
@@ -45,6 +45,8 @@ public class InliningContext {
public final Map<String, String> typeMapping; public final Map<String, String> typeMapping;
public final boolean isInliningLambda;
public InliningContext( public InliningContext(
Map<Integer, LambdaInfo> map, Map<Integer, LambdaInfo> map,
List<InvokeCall> accesses, List<InvokeCall> accesses,
@@ -54,9 +56,10 @@ public class InliningContext {
NameGenerator nameGenerator, NameGenerator nameGenerator,
CodegenContext startContext, CodegenContext startContext,
Call call, Call call,
Map<String, String> typeMapping Map<String, String> typeMapping,
boolean isInliningLambda
) { ) {
expresssionMap = map; expressionMap = map;
invokeCalls = accesses; invokeCalls = accesses;
constructorInvocation = invocation; constructorInvocation = invocation;
this.remapper = remapper; this.remapper = remapper;
@@ -65,16 +68,26 @@ public class InliningContext {
this.startContext = startContext; this.startContext = startContext;
this.call = call; this.call = call;
this.typeMapping = typeMapping; this.typeMapping = typeMapping;
this.isInliningLambda = isInliningLambda;
} }
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 subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) { public InliningContext subInlineLambda(NameGenerator generator) {
HashMap<String, String> newTypeMappings = new HashMap<String, String>(typeMapping); return subInline(generator, Collections.<String, String>emptyMap(), true);
newTypeMappings.putAll(additionalTypeMappings);
return new InliningContext(expresssionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call,
newTypeMappings);
} }
public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
return subInline(generator, additionalTypeMappings, isInliningLambda);
}
public InliningContext subInline(NameGenerator generator, Map<String, String> additionalTypeMappings, boolean isInliningLambda) {
Map<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
newTypeMappings.putAll(additionalTypeMappings);
return new InliningContext(expressionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call,
newTypeMappings, isInliningLambda);
}
} }
@@ -108,7 +108,7 @@ public class LambdaTransformer {
} }
} }
public void doTransform(ConstructorInvocation invocation) { public InlineResult doTransform(ConstructorInvocation invocation) {
ClassBuilder classBuilder = createClassBuilder(); ClassBuilder classBuilder = createClassBuilder();
//TODO: public visibility for inline function //TODO: public visibility for inline function
@@ -128,7 +128,7 @@ public class LambdaTransformer {
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, info.subInline(info.nameGenerator.subGenerator("lambda")), oldLambdaType,
remapper, isSameModule); 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); invokeVisitor.visitMaxs(-1, -1);
generateConstructorAndFields(classBuilder, builder, invocation); generateConstructorAndFields(classBuilder, builder, invocation);
@@ -150,6 +150,7 @@ public class LambdaTransformer {
classBuilder.done(); classBuilder.done();
invocation.setNewLambdaType(newLambdaType); invocation.setNewLambdaType(newLambdaType);
return result;
} }
private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder builder, @NotNull ConstructorInvocation invocation) { private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder builder, @NotNull ConstructorInvocation invocation) {
@@ -46,6 +46,8 @@ public class MethodInliner {
//current state //current state
private final Map<String, String> currentTypeMapping = new HashMap<String, String>(); private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
private final InlineResult result;
/* /*
* *
* @param node * @param node
@@ -68,14 +70,15 @@ public class MethodInliner {
this.lambdaFieldRemapper = lambdaFieldRemapper; this.lambdaFieldRemapper = lambdaFieldRemapper;
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
this.typeMapper = parent.state.getTypeMapper(); this.typeMapper = parent.state.getTypeMapper();
this.result = InlineResult.create();
} }
public void doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) { public InlineResult doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) {
doInline(adapter, remapper, new LambdaFieldRemapper(), true); return doInline(adapter, remapper, new LambdaFieldRemapper(), true);
} }
public void doInline( public InlineResult doInline(
MethodVisitor adapter, MethodVisitor adapter,
VarRemapper.ParamRemapper remapper, VarRemapper.ParamRemapper remapper,
LambdaFieldRemapper capturedRemapper, boolean remapReturn LambdaFieldRemapper capturedRemapper, boolean remapReturn
@@ -98,6 +101,7 @@ public class MethodInliner {
transformedNode.accept(visitor); transformedNode.accept(visitor);
visitor.visitLabel(end); visitor.visitLabel(end);
return result;
} }
private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) { private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) {
@@ -128,6 +132,11 @@ public class MethodInliner {
isSameModule, newLambdaType); isSameModule, newLambdaType);
transformer.doTransform(invocation); 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); Parameters lambdaParameters = info.addAllParameters(capturedRemapper);
setInlining(true); setInlining(true);
MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(), MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInlineLambda(
capturedRemapper, true /*cause all calls in same module as lambda*/); parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(),
capturedRemapper, true /*cause all calls in same module as lambda*/
);
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift); 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 //return value boxing/unboxing
Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();