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 =
new InliningInfo(expressionMap, null, null, null, state,
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
@@ -20,6 +20,8 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.Call;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -41,6 +43,8 @@ public class InliningInfo {
public final Call call;
public final Map<String, String> typeMapping;
public InliningInfo(
Map<Integer, LambdaInfo> map,
List<InlinableAccess> accesses,
@@ -49,7 +53,8 @@ public class InliningInfo {
GenerationState state,
NameGenerator nameGenerator,
CodegenContext startContext,
Call call
Call call,
Map<String, String> typeMapping
) {
expresssionMap = map;
inlinableAccesses = accesses;
@@ -59,9 +64,17 @@ public class InliningInfo {
this.nameGenerator = nameGenerator;
this.startContext = startContext;
this.call = call;
this.typeMapping = typeMapping;
}
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.VarInsnNode;
import org.jetbrains.jet.OutputFile;
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.*;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.resolve.name.FqName;
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.V1_6;
@@ -67,13 +67,13 @@ public class LambdaTransformer {
private String[] interfaces;
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.state = info.state;
this.typeMapper = state.getTypeMapper();
this.info = info;
this.oldLambdaType = Type.getObjectType(lambdaInternalName);
newLambdaType = Type.getObjectType(info.nameGenerator.genLambdaClassName());
this.newLambdaType = newLambdaType;
//try to find just compiled classes then in dependencies
ClassReader reader;
@@ -173,7 +173,8 @@ public class LambdaTransformer {
}
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) {
@@ -10,6 +10,8 @@ import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
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.analysis.*;
import org.jetbrains.jet.codegen.ClosureCodegen;
@@ -43,7 +45,7 @@ public class MethodInliner {
//keeps order
private final List<ConstructorInvocation> constructorInvocationList = new ArrayList<ConstructorInvocation>();
//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();
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;
@Override
@@ -116,24 +121,25 @@ public class MethodInliner {
invocation = iterator.next();
if (invocation.isInlinable()) {
LambdaTransformer transformer = new LambdaTransformer(invocation.getOwnerInternalName(), parent.subInline(parent.nameGenerator),
isSameModule);
//TODO: need poping of type but what to do with local funs???
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);
super.anew(transformer.getNewLambdaType());
constructorInvocation.put(invocation.getOwnerInternalName(), invocation);
} else {
super.anew(type);
}
super.anew(type);
} else {
super.anew(type);
}
}
//for local function support
@Override
public void checkcast(Type type) {
super.checkcast(changeOwnerIfLocalFun(type));
}
////for local function support
//@Override
//public void checkcast(Type type) {
// super.checkcast(changeOwnerIfLocalFun(type));
//}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
@@ -191,7 +197,7 @@ public class MethodInliner {
}
}
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);
}
}
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();
}
}