From 3f9125cf08be5c9dc1830ff5cfdeaeea42eb1706 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Fri, 14 Feb 2014 14:06:28 +0400 Subject: [PATCH] Recursive lambdas regeneration/copy --- .../jet/codegen/asm/InlineCodegen.java | 2 +- .../jet/codegen/asm/InliningInfo.java | 17 ++- .../jet/codegen/asm/LambdaTransformer.java | 17 +-- .../jet/codegen/asm/MethodInliner.java | 56 +++----- .../jet/codegen/asm/TypeRemapper.java | 53 ++++++++ .../codegen/inline/RemappingClassBuilder.java | 122 ++++++++++++++++++ 6 files changed, 220 insertions(+), 47 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/asm/TypeRemapper.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/inline/RemappingClassBuilder.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java index c32646e4828..f9ec394346d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java @@ -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.emptyMap()); MethodInliner inliner = new MethodInliner(node, parameters, info, null, new LambdaFieldRemapper(), isSameModule); //with captured diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningInfo.java index 9386382df2f..5366bbbe38e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningInfo.java @@ -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 typeMapping; + public InliningInfo( Map map, List accesses, @@ -49,7 +53,8 @@ public class InliningInfo { GenerationState state, NameGenerator nameGenerator, CodegenContext startContext, - Call call + Call call, + Map 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.emptyMap()); + } + + public InliningInfo subInline(NameGenerator generator, Map additionalTypeMappings) { + HashMap newTypeMappings = new HashMap(typeMapping); + newTypeMappings.putAll(additionalTypeMappings); + return new InliningInfo(expresssionMap, inlinableAccesses, constructorInvocation, remapper, state, generator, startContext, call, + newTypeMappings); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java index 3074c01e855..668f5cd1bd3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/LambdaTransformer.java @@ -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) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java index 9607eb68730..df099d71153 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/MethodInliner.java @@ -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 constructorInvocationList = new ArrayList(); //current state - private final Map constructorInvocation = new LinkedHashMap(); + private final Map currentTypeMapping = new HashMap(); /* * @@ -107,7 +109,10 @@ public class MethodInliner { final Iterator 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; - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/TypeRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/TypeRemapper.java new file mode 100644 index 00000000000..601811df085 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/TypeRemapper.java @@ -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 typeMapping; + + private final boolean isSameModule; + + //typeMapping could be changed outside through method processing + public TypeRemapper(@NotNull Map 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; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemappingClassBuilder.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemappingClassBuilder.java new file mode 100644 index 00000000000..3e8ce976978 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RemappingClassBuilder.java @@ -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(); + } +}