Recursive lambdas regeneration/copy
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user