Code clean

This commit is contained in:
Mikhael Bogdanov
2014-02-26 18:39:24 +04:00
parent 8ac48b746c
commit 55fbdbd302
6 changed files with 62 additions and 54 deletions
@@ -33,9 +33,9 @@ public class ConstructorInvocation {
private String newConstructorDescriptor; private String newConstructorDescriptor;
private List<CapturedParamInfo> recaptured; private List<CapturedParamInfo> allRecapturedParameters;
private Map<String, LambdaInfo> recapturedLambdas; private Map<String, LambdaInfo> capturedLambdasToInline;
ConstructorInvocation(String ownerInternalName, Map<Integer, LambdaInfo> lambdasToInline, boolean isSameModule) { ConstructorInvocation(String ownerInternalName, Map<Integer, LambdaInfo> lambdasToInline, boolean isSameModule) {
this.ownerInternalName = ownerInternalName; this.ownerInternalName = ownerInternalName;
@@ -55,7 +55,6 @@ public class ConstructorInvocation {
return lambdasToInline; return lambdasToInline;
} }
public Type getNewLambdaType() { public Type getNewLambdaType() {
return newLambdaType; return newLambdaType;
} }
@@ -72,19 +71,19 @@ public class ConstructorInvocation {
this.newConstructorDescriptor = newConstructorDescriptor; this.newConstructorDescriptor = newConstructorDescriptor;
} }
public List<CapturedParamInfo> getRecaptured() { public List<CapturedParamInfo> getAllRecapturedParameters() {
return recaptured; return allRecapturedParameters;
} }
public void setRecaptured(List<CapturedParamInfo> recaptured) { public void setAllRecapturedParameters(List<CapturedParamInfo> allRecapturedParameters) {
this.recaptured = recaptured; this.allRecapturedParameters = allRecapturedParameters;
} }
public Map<String, LambdaInfo> getRecapturedLambdas() { public Map<String, LambdaInfo> getCapturedLambdasToInline() {
return recapturedLambdas; return capturedLambdasToInline;
} }
public void setRecapturedLambdas(Map<String, LambdaInfo> recapturedLambdas) { public void setCapturedLambdasToInline(Map<String, LambdaInfo> capturedLambdasToInline) {
this.recapturedLambdas = recapturedLambdas; this.capturedLambdasToInline = capturedLambdasToInline;
} }
} }
@@ -207,7 +207,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize); VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(parameters, initialFrameSize);
inliner.doTransformAndMerge(codegen.v, remapper); inliner.doInline(codegen.v, remapper);
} }
@@ -87,7 +87,7 @@ public class InlineCodegenUtil {
FqName namespaceFqName = FqName namespaceFqName =
PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) parentDeclatation).getFqName()).parent().child( PackageClassUtils.getPackageClassFqName(((PackageFragmentDescriptor) parentDeclatation).getFqName()).parent().child(
name); name);
file = findVirtualFile(state.getProject(), namespaceFqName, true); file = findVirtualFileWithHeader(state.getProject(), namespaceFqName);
} else { } else {
assert false : "Function in namespace should have implClassName property in proto: " + deserializedDescriptor; assert false : "Function in namespace should have implClassName property in proto: " + deserializedDescriptor;
} }
@@ -103,13 +103,15 @@ public class InlineCodegenUtil {
} }
@Nullable @Nullable
public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull FqName containerFqName, boolean onlyKotlin) { public static VirtualFile findVirtualFileWithHeader(@NotNull Project project, @NotNull FqName containerFqName) {
VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class); VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class);
if (onlyKotlin) { return fileFinder.findVirtualFileWithHeader(containerFqName);
return fileFinder.findVirtualFileWithHeader(containerFqName); }
} else {
return fileFinder.findVirtualFile(containerFqName.asString().replace('.', '/')); @Nullable
} public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalName) {
VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class);
return fileFinder.findVirtualFile(internalName);
} }
//TODO: navigate to inner classes //TODO: navigate to inner classes
@@ -185,7 +187,7 @@ public class InlineCodegenUtil {
if (containerFqName == null) { if (containerFqName == null) {
return null; return null;
} }
return findVirtualFile(project, containerFqName, true); return findVirtualFileWithHeader(project, containerFqName);
} }
@@ -27,10 +27,12 @@ import org.jetbrains.asm4.tree.FieldInsnNode;
import org.jetbrains.asm4.tree.MethodNode; import org.jetbrains.asm4.tree.MethodNode;
import org.jetbrains.asm4.tree.VarInsnNode; import org.jetbrains.asm4.tree.VarInsnNode;
import org.jetbrains.jet.OutputFile; import org.jetbrains.jet.OutputFile;
import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.ClosureCodegen;
import org.jetbrains.jet.codegen.FieldInfo;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -55,8 +57,6 @@ public class LambdaTransformer {
private final InliningInfo info; private final InliningInfo info;
private final Map<String, Integer> paramMapping = new HashMap<String, Integer>();
private final Type oldLambdaType; private final Type oldLambdaType;
private final Type newLambdaType; private final Type newLambdaType;
@@ -82,7 +82,7 @@ public class LambdaTransformer {
if (outputFile != null) { if (outputFile != null) {
reader = new ClassReader(outputFile.asByteArray()); reader = new ClassReader(outputFile.asByteArray());
} else { } else {
VirtualFile file = InlineCodegenUtil.findVirtualFile(state.getProject(), new FqName(lambdaInternalName.replace('/', '.')), false); VirtualFile file = InlineCodegenUtil.findVirtualFile(state.getProject(), lambdaInternalName);
if (file == null) { if (file == null) {
throw new RuntimeException("Couldn't find virtual file for " + lambdaInternalName); throw new RuntimeException("Couldn't find virtual file for " + lambdaInternalName);
} }
@@ -93,6 +93,7 @@ public class LambdaTransformer {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
//TODO rewrite to one step
constructor = getMethodNode(reader, true, false); constructor = getMethodNode(reader, true, false);
invoke = getMethodNode(reader, false, false); invoke = getMethodNode(reader, false, false);
bridge = getMethodNode(reader, false, true); bridge = getMethodNode(reader, false, true);
@@ -110,6 +111,7 @@ public class LambdaTransformer {
public void doTransform(ConstructorInvocation invocation) { public void doTransform(ConstructorInvocation invocation) {
ClassBuilder classBuilder = createClassBuilder(); ClassBuilder classBuilder = createClassBuilder();
//TODO: public visibility for inline function
classBuilder.defineClass(null, classBuilder.defineClass(null,
V1_6, V1_6,
classAccess, classAccess,
@@ -122,10 +124,10 @@ public class LambdaTransformer {
Parameters parameters = getLambdaParameters(builder, invocation); Parameters parameters = getLambdaParameters(builder, invocation);
MethodVisitor invokeVisitor = newMethod(classBuilder, invoke); MethodVisitor invokeVisitor = newMethod(classBuilder, invoke);
InlineFieldRemapper remapper = new InlineFieldRemapper(oldLambdaType.getInternalName(), newLambdaType.getInternalName(), parameters, invocation.getRecapturedLambdas()); InlineFieldRemapper remapper = new InlineFieldRemapper(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.doTransformAndMerge(invokeVisitor, new VarRemapper.ParamRemapper(parameters, 0), remapper, false); 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);
@@ -162,6 +164,7 @@ public class LambdaTransformer {
AsmUtil.genClosureFields(newConstructorSignature, classBuilder); AsmUtil.genClosureFields(newConstructorSignature, classBuilder);
//TODO for inline method make public class
Method newConstructor = ClosureCodegen.generateConstructor(classBuilder, fields, null, Type.getObjectType(superName), state, AsmUtil.NO_FLAG_PACKAGE_PRIVATE); Method newConstructor = ClosureCodegen.generateConstructor(classBuilder, fields, null, Type.getObjectType(superName), state, AsmUtil.NO_FLAG_PACKAGE_PRIVATE);
invocation.setNewConstructorDescriptor(newConstructor.getDescriptor()); invocation.setNewConstructorDescriptor(newConstructor.getDescriptor());
} }
@@ -173,7 +176,7 @@ public class LambdaTransformer {
} }
private ClassBuilder createClassBuilder() { private ClassBuilder createClassBuilder() {
return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, info.call.getCalleeExpression().getContainingFile()), return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, info.call.getCallElement().getContainingFile()),
new TypeRemapper(info.typeMapping, isSameModule)); new TypeRemapper(info.typeMapping, isSameModule));
} }
@@ -188,7 +191,7 @@ public class LambdaTransformer {
); );
} }
private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) { private static void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) {
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline(); Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
AbstractInsnNode cur = constructor.instructions.getFirst(); AbstractInsnNode cur = constructor.instructions.getFirst();
@@ -197,34 +200,35 @@ public class LambdaTransformer {
while (cur != null) { while (cur != null) {
if (cur.getType() == AbstractInsnNode.FIELD_INSN) { if (cur.getType() == AbstractInsnNode.FIELD_INSN) {
FieldInsnNode fieldNode = (FieldInsnNode) cur; FieldInsnNode fieldNode = (FieldInsnNode) cur;
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null);
assert fieldNode.getPrevious() instanceof VarInsnNode : "Previous instruction should be VarInsnNode but was " + fieldNode.getPrevious();
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious(); VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
int varIndex = previous.var; int varIndex = previous.var;
paramMapping.put(fieldNode.name, varIndex); LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
if (lambdaInfo != null) {
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null); info.setLambda(lambdaInfo);
LambdaInfo LambdaInfo = indexToLambda.get(varIndex); additionalCaptured.add(lambdaInfo);
if (LambdaInfo != null) {
info.setLambda(LambdaInfo);
additionalCaptured.add(LambdaInfo);
} }
} }
cur = cur.getNext(); cur = cur.getNext();
} }
Map<String, LambdaInfo> recapturedLambdas = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter //For all inlined lambdas add their captured parameters
List<CapturedParamInfo> recaptured = new ArrayList<CapturedParamInfo>(); //TODO: some of such parameters could be skipped - we should perform additional analysis
Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter
List<CapturedParamInfo> allRecapturedParameters = new ArrayList<CapturedParamInfo>();
for (LambdaInfo info : additionalCaptured) { for (LambdaInfo info : additionalCaptured) {
List<CapturedParamInfo> vars = info.getCapturedVars(); for (CapturedParamInfo var : info.getCapturedVars()) {
for (CapturedParamInfo var : vars) {
CapturedParamInfo recapturedParamInfo = builder.addCapturedParam(getNewFieldName(var.getFieldName()), var.getType(), true, var); CapturedParamInfo recapturedParamInfo = builder.addCapturedParam(getNewFieldName(var.getFieldName()), var.getType(), true, var);
recapturedParamInfo.setRecapturedFrom(info); recapturedParamInfo.setRecapturedFrom(info);
recaptured.add(var); allRecapturedParameters.add(var);
} }
recapturedLambdas.put(info.getLambdaClassType().getInternalName(), info); capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
} }
invocation.setRecaptured(recaptured); invocation.setAllRecapturedParameters(allRecapturedParameters);
invocation.setRecapturedLambdas(recapturedLambdas); invocation.setCapturedLambdasToInline(capturedLambdasToInline);
} }
@Nullable @Nullable
@@ -244,7 +248,8 @@ public class LambdaTransformer {
@Override @Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
boolean isConstructorMethod = "<init>".equals(name); boolean isConstructorMethod = "<init>".equals(name);
if (findConstructor && isConstructorMethod || (!findConstructor && !isConstructorMethod && ((access & Opcodes.ACC_BRIDGE) == (findBridge ? Opcodes.ACC_BRIDGE : 0)))) { boolean isBridge = (access & Opcodes.ACC_BRIDGE) != 0;
if (findConstructor && isConstructorMethod || (!findConstructor && !isConstructorMethod && (isBridge == findBridge))) {
assert methodNode[0] == null : "Wrong lambda/sam structure: " + methodNode[0].name + " conflicts with " + name; assert methodNode[0] == null : "Wrong lambda/sam structure: " + methodNode[0].name + " conflicts with " + name;
return methodNode[0] = new MethodNode(access, name, desc, signature, exceptions); return methodNode[0] = new MethodNode(access, name, desc, signature, exceptions);
} }
@@ -259,10 +264,6 @@ public class LambdaTransformer {
return methodNode[0]; return methodNode[0];
} }
public Type getNewLambdaType() {
return newLambdaType;
}
public static String getNewFieldName(String oldName) { public static String getNewFieldName(String oldName) {
return oldName + "$inlined"; return oldName + "$inlined";
} }
@@ -71,11 +71,11 @@ public class MethodInliner {
} }
public void doTransformAndMerge(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) { public void doInline(MethodVisitor adapter, VarRemapper.ParamRemapper remapper) {
doTransformAndMerge(adapter, remapper, new LambdaFieldRemapper(), true); doInline(adapter, remapper, new LambdaFieldRemapper(), true);
} }
public void doTransformAndMerge( public void doInline(
MethodVisitor adapter, MethodVisitor adapter,
VarRemapper.ParamRemapper remapper, VarRemapper.ParamRemapper remapper,
LambdaFieldRemapper capturedRemapper, boolean remapReturn LambdaFieldRemapper capturedRemapper, boolean remapReturn
@@ -158,7 +158,7 @@ public class MethodInliner {
capturedRemapper, true /*cause all calls in same module as lambda*/); 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.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver inliner.doInline(this.mv, remapper); //TODO add skipped this and receiver
//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();
@@ -170,7 +170,7 @@ public class MethodInliner {
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name; assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
if (invocation.shouldRegenerate()) { if (invocation.shouldRegenerate()) {
//put additional captured parameters on stack //put additional captured parameters on stack
List<CapturedParamInfo> recaptured = invocation.getRecaptured(); List<CapturedParamInfo> recaptured = invocation.getAllRecapturedParameters();
List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured(); List<CapturedParamInfo> contextCaptured = MethodInliner.this.parameters.getCaptured();
for (CapturedParamInfo capturedParamInfo : recaptured) { for (CapturedParamInfo capturedParamInfo : recaptured) {
CapturedParamInfo result = null; CapturedParamInfo result = null;
@@ -92,4 +92,10 @@ public class RemapVisitor extends InstructionAdapter {
super.visitFieldInsn(opcode, owner, name, desc); super.visitFieldInsn(opcode, owner, name, desc);
} }
} }
//TODO not skip for lambdas
@Override
public void visitLineNumber(int line, Label start) {
}
} }