Recursive lambdas regeneration/copy

This commit is contained in:
Mikhael Bogdanov
2014-02-14 14:06:28 +04:00
parent e695f0a516
commit 3f9125cf08
6 changed files with 220 additions and 47 deletions
@@ -199,7 +199,7 @@ public class InlineCodegen implements ParentCodegenAware, Inliner {
InliningInfo info = InliningInfo info =
new InliningInfo(expressionMap, null, null, null, state, new InliningInfo(expressionMap, null, null, null, state,
codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()), codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()),
codegen.getContext(), call); codegen.getContext(), call, Collections.<String, String>emptyMap());
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
@@ -20,6 +20,8 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.Call;
import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -41,6 +43,8 @@ public class InliningInfo {
public final Call call; public final Call call;
public final Map<String, String> typeMapping;
public InliningInfo( public InliningInfo(
Map<Integer, LambdaInfo> map, Map<Integer, LambdaInfo> map,
List<InlinableAccess> accesses, List<InlinableAccess> accesses,
@@ -49,7 +53,8 @@ public class InliningInfo {
GenerationState state, GenerationState state,
NameGenerator nameGenerator, NameGenerator nameGenerator,
CodegenContext startContext, CodegenContext startContext,
Call call Call call,
Map<String, String> typeMapping
) { ) {
expresssionMap = map; expresssionMap = map;
inlinableAccesses = accesses; inlinableAccesses = accesses;
@@ -59,9 +64,17 @@ public class InliningInfo {
this.nameGenerator = nameGenerator; this.nameGenerator = nameGenerator;
this.startContext = startContext; this.startContext = startContext;
this.call = call; this.call = call;
this.typeMapping = typeMapping;
} }
public InliningInfo subInline(NameGenerator generator) { public InliningInfo subInline(NameGenerator generator) {
return new InliningInfo(expresssionMap, inlinableAccesses, constructorInvocation, remapper, state, generator, startContext, call); return subInline(generator, Collections.<String, String>emptyMap());
}
public InliningInfo subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
HashMap<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
newTypeMappings.putAll(additionalTypeMappings);
return new InliningInfo(expresssionMap, inlinableAccesses, constructorInvocation, remapper, state, generator, startContext, call,
newTypeMappings);
} }
} }
@@ -27,16 +27,16 @@ 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.AsmUtil; import org.jetbrains.jet.codegen.*;
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 org.jetbrains.jet.lang.resolve.name.FqName;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.jetbrains.asm4.Opcodes.ASM4; import static org.jetbrains.asm4.Opcodes.ASM4;
import static org.jetbrains.asm4.Opcodes.V1_6; import static org.jetbrains.asm4.Opcodes.V1_6;
@@ -67,13 +67,13 @@ public class LambdaTransformer {
private String[] interfaces; private String[] interfaces;
private boolean isSameModule; private boolean isSameModule;
public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule) { public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule, Type newLambdaType) {
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
this.state = info.state; this.state = info.state;
this.typeMapper = state.getTypeMapper(); this.typeMapper = state.getTypeMapper();
this.info = info; this.info = info;
this.oldLambdaType = Type.getObjectType(lambdaInternalName); this.oldLambdaType = Type.getObjectType(lambdaInternalName);
newLambdaType = Type.getObjectType(info.nameGenerator.genLambdaClassName()); this.newLambdaType = newLambdaType;
//try to find just compiled classes then in dependencies //try to find just compiled classes then in dependencies
ClassReader reader; ClassReader reader;
@@ -173,7 +173,8 @@ public class LambdaTransformer {
} }
private ClassBuilder createClassBuilder() { private ClassBuilder createClassBuilder() {
return state.getFactory().forLambdaInlining(newLambdaType, info.call.getCalleeExpression().getContainingFile()); return new RemappingClassBuilder(state.getFactory().forLambdaInlining(newLambdaType, info.call.getCalleeExpression().getContainingFile()),
new TypeRemapper(info.typeMapping, isSameModule));
} }
private static MethodVisitor newMethod(ClassBuilder builder, MethodNode original) { private static MethodVisitor newMethod(ClassBuilder builder, MethodNode original) {
@@ -10,6 +10,8 @@ import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.asm4.commons.Remapper;
import org.jetbrains.asm4.commons.RemappingMethodAdapter;
import org.jetbrains.asm4.tree.*; import org.jetbrains.asm4.tree.*;
import org.jetbrains.asm4.tree.analysis.*; import org.jetbrains.asm4.tree.analysis.*;
import org.jetbrains.jet.codegen.ClosureCodegen; import org.jetbrains.jet.codegen.ClosureCodegen;
@@ -43,7 +45,7 @@ public class MethodInliner {
//keeps order //keeps order
private final List<ConstructorInvocation> constructorInvocationList = new ArrayList<ConstructorInvocation>(); private final List<ConstructorInvocation> constructorInvocationList = new ArrayList<ConstructorInvocation>();
//current state //current state
private final Map<String, ConstructorInvocation> constructorInvocation = new LinkedHashMap<String, ConstructorInvocation>(); private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
/* /*
* *
@@ -107,7 +109,10 @@ public class MethodInliner {
final Iterator<ConstructorInvocation> iterator = constructorInvocationList.iterator(); final Iterator<ConstructorInvocation> iterator = constructorInvocationList.iterator();
InlineAdapter inliner = new InlineAdapter(resultNode, parameters.totalSize()) { RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode,
new TypeRemapper(currentTypeMapping, isSameModule));
InlineAdapter inliner = new InlineAdapter(remappingMethodAdapter, parameters.totalSize()) {
private ConstructorInvocation invocation; private ConstructorInvocation invocation;
@Override @Override
@@ -116,24 +121,25 @@ public class MethodInliner {
invocation = iterator.next(); invocation = iterator.next();
if (invocation.isInlinable()) { if (invocation.isInlinable()) {
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(), parent.subInline(parent.nameGenerator), //TODO: need poping of type but what to do with local funs???
isSameModule); Type newLambdaType = Type.getObjectType(parent.nameGenerator.genLambdaClassName());
currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName());
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(), parent.subInline(parent.nameGenerator, currentTypeMapping),
isSameModule, newLambdaType);
transformer.doTransform(invocation); transformer.doTransform(invocation);
super.anew(transformer.getNewLambdaType());
constructorInvocation.put(invocation.getOwnerInternalName(), invocation);
} else {
super.anew(type);
} }
super.anew(type);
} else { } else {
super.anew(type); super.anew(type);
} }
} }
//for local function support ////for local function support
@Override //@Override
public void checkcast(Type type) { //public void checkcast(Type type) {
super.checkcast(changeOwnerIfLocalFun(type)); // super.checkcast(changeOwnerIfLocalFun(type));
} //}
@Override @Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) { public void visitMethodInsn(int opcode, String owner, String name, String desc) {
@@ -191,7 +197,7 @@ public class MethodInliner {
} }
} }
else { else {
super.visitMethodInsn(opcode, changeOwnerIfLocalFun(owner), name, desc); super.visitMethodInsn(opcode, /*changeOwnerIfLocalFun(*/owner/*)*/, name, desc);
} }
} }
}; };
@@ -525,26 +531,4 @@ public class MethodInliner {
mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift); mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift);
} }
} }
private Type changeOwnerIfLocalFun(Type oldType) {
if (isLambdaClass(oldType.getInternalName())) {
ConstructorInvocation invocation1 = constructorInvocation.get(oldType.getInternalName());
if (invocation1 != null && invocation1.isInlinable()) {
return invocation1.getNewLambdaType();
}
}
return oldType;
}
private String changeOwnerIfLocalFun(String oldType) {
if (isLambdaClass(oldType)) {
ConstructorInvocation invocation1 = constructorInvocation.get(oldType);
if (invocation1 != null && invocation1.isInlinable()) {
return invocation1.getNewLambdaType().getInternalName();
}
}
return oldType;
}
} }
@@ -0,0 +1,53 @@
/*
* 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.asm;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.commons.Remapper;
import java.util.Map;
public class TypeRemapper extends Remapper {
@NotNull
private final Map<String, String> typeMapping;
private final boolean isSameModule;
//typeMapping could be changed outside through method processing
public TypeRemapper(@NotNull Map<String, String> typeMapping, boolean isSameModule) {
this.typeMapping = typeMapping;
this.isSameModule = isSameModule;
}
@Override
public String map(String type) {
String newType = typeMapping.get(type);
if (newType != null) {
return newType;
}
/*if (!isSameModule) {
int indexOfMinus = type.indexOf("-");
if (indexOfMinus > 0) {
//type.substring(0, indexOfMinus)
}
}*/
return type;
}
}
@@ -0,0 +1,122 @@
/*
* 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 com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.ClassVisitor;
import org.jetbrains.asm4.FieldVisitor;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.commons.*;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.JvmSerializationBindings;
public class RemappingClassBuilder implements ClassBuilder {
private final ClassBuilder builder;
private final Remapper remapper;
public RemappingClassBuilder(@NotNull ClassBuilder builder, @NotNull Remapper remapper) {
this.builder = builder;
this.remapper = remapper;
}
@Override
@NotNull
public FieldVisitor newField(
@Nullable PsiElement origin,
int access,
@NotNull String name,
@NotNull String desc,
@Nullable String signature,
@Nullable Object value
) {
return new RemappingFieldAdapter(builder.newField(origin, access, name, remapper.mapDesc(desc), signature, value), remapper);
}
@Override
@NotNull
public MethodVisitor newMethod(
@Nullable PsiElement origin,
int access,
@NotNull String name,
@NotNull String desc,
@Nullable String signature,
@Nullable String[] exceptions
) {
return new RemappingMethodAdapter(access, desc, builder.newMethod(origin, access, name, remapper.mapMethodDesc(desc), signature, exceptions), remapper);
}
@Override
@NotNull
public JvmSerializationBindings getSerializationBindings() {
return builder.getSerializationBindings();
}
@Override
@NotNull
public AnnotationVisitor newAnnotation(@NotNull String desc, boolean visible) {
return new RemappingAnnotationAdapter(builder.newAnnotation(remapper.mapDesc(desc), visible), remapper);
}
@Override
public void done() {
builder.done();
}
@Override
@NotNull
public ClassVisitor getVisitor() {
return new RemappingClassAdapter(builder.getVisitor(), remapper);
}
@Override
public void defineClass(
@Nullable PsiElement origin,
int version,
int access,
@NotNull String name,
@Nullable String signature,
@NotNull String superName,
@NotNull String[] interfaces
) {
builder.defineClass(origin, version, access, name, signature, superName, interfaces);
}
@Override
public void visitSource(@NotNull String name, @Nullable String debug) {
builder.visitSource(name, debug);
}
@Override
public void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc) {
builder.visitOuterClass(owner, name, desc);
}
@Override
public void visitInnerClass(@NotNull String name, @Nullable String outerName, @Nullable String innerName, int access) {
builder.visitInnerClass(name, outerName, innerName, access);
}
@Override
@NotNull
public String getThisName() {
return builder.getThisName();
}
}