diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectGeneration.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectRegenerationInfo.java similarity index 92% rename from compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectGeneration.java rename to compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectRegenerationInfo.java index 504618f4868..ca58982a45c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectGeneration.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectRegenerationInfo.java @@ -24,7 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class AnonymousObjectGeneration { +public class AnonymousObjectRegenerationInfo extends RegenerationInfo { private final String ownerInternalName; @@ -45,7 +45,7 @@ public class AnonymousObjectGeneration { private final boolean alreadyRegenerated; private final boolean isStaticOrigin; - AnonymousObjectGeneration( + AnonymousObjectRegenerationInfo( @NotNull String ownerInternalName, boolean needReification, @NotNull Map lambdasToInline, @@ -63,7 +63,7 @@ public class AnonymousObjectGeneration { this.isStaticOrigin = isStaticOrigin; } - public AnonymousObjectGeneration( + public AnonymousObjectRegenerationInfo( @NotNull String ownerInternalName, boolean needReification, boolean alreadyRegenerated, boolean isStaticOrigin @@ -74,10 +74,13 @@ public class AnonymousObjectGeneration { ); } + @NotNull + @Override public String getOldClassName() { return ownerInternalName; } + @Override public boolean shouldRegenerate(boolean isSameModule) { return !alreadyRegenerated && ( !lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated || needReification @@ -88,8 +91,10 @@ public class AnonymousObjectGeneration { return lambdasToInline; } - public Type getNewLambdaType() { - return newLambdaType; + @NotNull + @Override + public String getNewClassName() { + return newLambdaType.getInternalName(); } public void setNewLambdaType(Type newLambdaType) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java index 3c80e6b9838..51b1ecc084d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java @@ -34,14 +34,12 @@ import java.util.*; import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.isThis0; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; -public class AnonymousObjectTransformer { +public class AnonymousObjectTransformer extends ObjectTransformer { protected final GenerationState state; protected final KotlinTypeMapper typeMapper; - private final InlineResult transformationResult; - private MethodNode constructor; private String sourceInfo; @@ -56,36 +54,33 @@ public class AnonymousObjectTransformer { private final Type newLambdaType; - private final ClassReader reader; - private final boolean isSameModule; private final Map> fieldNames = new HashMap>(); public AnonymousObjectTransformer( - @NotNull String objectInternalName, + @NotNull AnonymousObjectRegenerationInfo regenerationInfo, @NotNull InliningContext inliningContext, boolean isSameModule, @NotNull Type newLambdaType ) { + super(regenerationInfo, inliningContext.state); this.isSameModule = isSameModule; this.state = inliningContext.state; this.typeMapper = state.getTypeMapper(); this.inliningContext = inliningContext; - this.oldObjectType = Type.getObjectType(objectInternalName); + this.oldObjectType = Type.getObjectType(regenerationInfo.getOldClassName()); this.newLambdaType = newLambdaType; - - reader = InlineCodegenUtil.buildClassReaderByInternalName(state, objectInternalName); - transformationResult = InlineResult.create(); } + @Override @NotNull - public InlineResult doTransform(@NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) { + public InlineResult doTransform(@NotNull AnonymousObjectRegenerationInfo regenerationInfo, @NotNull FieldRemapper parentRemapper) { final List innerClassNodes = new ArrayList(); - ClassBuilder classBuilder = createClassBuilder(); + ClassBuilder classBuilder = createRemappingClassBuilderViaFactory(inliningContext); final List methodsToTransform = new ArrayList(); - reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { + createClassReader().accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { @Override public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name); @@ -160,13 +155,13 @@ public class AnonymousObjectTransformer { ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); List additionalFakeParams = extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, - anonymousObjectGen, parentRemapper); + regenerationInfo, parentRemapper); List deferringMethods = new ArrayList(); for (MethodNode next : methodsToTransform) { MethodVisitor deferringVisitor = newMethod(classBuilder, next); InlineResult funResult = - inlineMethodAndUpdateGlobalResult(anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); + inlineMethodAndUpdateGlobalResult(regenerationInfo, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); Type returnType = Type.getReturnType(next.desc); if (!AsmUtil.isPrimitive(returnType)) { @@ -183,7 +178,7 @@ public class AnonymousObjectTransformer { method.visitEnd(); } - generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams); + generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, regenerationInfo, parentRemapper, additionalFakeParams); SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); @@ -196,7 +191,7 @@ public class AnonymousObjectTransformer { classBuilder.done(); - anonymousObjectGen.setNewLambdaType(newLambdaType); + regenerationInfo.setNewLambdaType(newLambdaType); return transformationResult; } @@ -207,14 +202,14 @@ public class AnonymousObjectTransformer { @NotNull private InlineResult inlineMethodAndUpdateGlobalResult( - @NotNull AnonymousObjectGeneration anonymousObjectGen, + @NotNull AnonymousObjectRegenerationInfo regenerationInfo, @NotNull FieldRemapper parentRemapper, @NotNull MethodVisitor deferringVisitor, @NotNull MethodNode next, @NotNull ParametersBuilder allCapturedParamBuilder, boolean isConstructor ) { - InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor); + InlineResult funResult = inlineMethod(regenerationInfo, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor); transformationResult.addAllClassesToRemove(funResult); transformationResult.getReifiedTypeParametersUsages().mergeAll(funResult.getReifiedTypeParametersUsages()); return funResult; @@ -222,7 +217,7 @@ public class AnonymousObjectTransformer { @NotNull private InlineResult inlineMethod( - @NotNull AnonymousObjectGeneration anonymousObjectGen, + @NotNull AnonymousObjectRegenerationInfo regenerationInfo, @NotNull FieldRemapper parentRemapper, @NotNull MethodVisitor deferringVisitor, @NotNull MethodNode sourceNode, @@ -234,7 +229,7 @@ public class AnonymousObjectTransformer { RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(), - parameters, anonymousObjectGen.getCapturedLambdasToInline(), + parameters, regenerationInfo.getCapturedLambdasToInline(), parentRemapper, isConstructor); MethodInliner inliner = @@ -244,12 +239,12 @@ public class AnonymousObjectTransformer { inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), remapper, isSameModule, - "Transformer for " + anonymousObjectGen.getOldClassName(), + "Transformer for " + regenerationInfo.getOldClassName(), sourceMapper, new InlineCallSiteInfo( - anonymousObjectGen.getOldClassName(), + regenerationInfo.getOldClassName(), sourceNode.name, - isConstructor ? anonymousObjectGen.getNewConstructorDescriptor() : sourceNode.desc), + isConstructor ? regenerationInfo.getNewConstructorDescriptor() : sourceNode.desc), null ); @@ -263,7 +258,7 @@ public class AnonymousObjectTransformer { @NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder constructorInlineBuilder, - @NotNull AnonymousObjectGeneration anonymousObjectGen, + @NotNull AnonymousObjectRegenerationInfo regenerationInfo, @NotNull FieldRemapper parentRemapper, @NotNull List constructorAdditionalFakeParams ) { @@ -291,7 +286,7 @@ public class AnonymousObjectTransformer { String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()])); //TODO for inline method make public class - anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor); + regenerationInfo.setNewConstructorDescriptor(constructorDescriptor); MethodVisitor constructorVisitor = classBuilder.newMethod(NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "", constructorDescriptor, @@ -329,7 +324,7 @@ public class AnonymousObjectTransformer { } } - inlineMethodAndUpdateGlobalResult(anonymousObjectGen, parentRemapper, capturedFieldInitializer, constructor, constructorInlineBuilder, true); + inlineMethodAndUpdateGlobalResult(regenerationInfo, parentRemapper, capturedFieldInitializer, constructor, constructorInlineBuilder, true); constructorVisitor.visitEnd(); AsmUtil.genClosureFields(TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder); } @@ -346,16 +341,6 @@ public class AnonymousObjectTransformer { return builder.buildParameters(); } - @NotNull - private ClassBuilder createClassBuilder() { - ClassBuilder classBuilder = state.getFactory().newVisitor(NO_ORIGIN, newLambdaType, inliningContext.getRoot().callElement.getContainingFile()); - - return new RemappingClassBuilder( - classBuilder, - new AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.getRoot().typeParameterMappings == null, transformationResult) - ); - } - @NotNull private static DeferredMethodVisitor newMethod(@NotNull final ClassBuilder builder, @NotNull final MethodNode original) { return new DeferredMethodVisitor( @@ -383,20 +368,20 @@ public class AnonymousObjectTransformer { @NotNull MethodNode constructor, @NotNull ParametersBuilder capturedParamBuilder, @NotNull ParametersBuilder constructorParamBuilder, - @NotNull final AnonymousObjectGeneration anonymousObjectGen, + @NotNull final AnonymousObjectRegenerationInfo regenerationInfo, @NotNull FieldRemapper parentFieldRemapper ) { CapturedParamOwner owner = new CapturedParamOwner() { @Override public Type getType() { - return Type.getObjectType(anonymousObjectGen.getOldClassName()); + return Type.getObjectType(regenerationInfo.getOldClassName()); } }; Set capturedLambdas = new LinkedHashSet(); //captured var of inlined parameter List constructorAdditionalFakeParams = new ArrayList(); - Map indexToLambda = anonymousObjectGen.getLambdasToInline(); + Map indexToLambda = regenerationInfo.getLambdasToInline(); Set capturedParams = new HashSet(); //load captured parameters and patch instruction list (NB: there is also could be object fields) @@ -439,7 +424,7 @@ public class AnonymousObjectTransformer { } constructorParamBuilder.addThis(oldObjectType, false); - String constructorDesc = anonymousObjectGen.getConstructorDesc(); + String constructorDesc = regenerationInfo.getConstructorDesc(); if (constructorDesc == null) { // in case of anonymous object with empty closure @@ -514,8 +499,8 @@ public class AnonymousObjectTransformer { constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed); } - anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters); - anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline); + regenerationInfo.setAllRecapturedParameters(allRecapturedParameters); + regenerationInfo.setCapturedLambdasToInline(capturedLambdasToInline); return constructorAdditionalFakeParams; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index 218f677fd0b..f95b78e4366 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -63,7 +63,7 @@ public class MethodInliner { private final List invokeCalls = new ArrayList(); //keeps order - private final List anonymousObjectGenerations = new ArrayList(); + private final List anonymousObjectRegenerations = new ArrayList(); //current state private final Map currentTypeMapping = new HashMap(); @@ -160,7 +160,7 @@ public class MethodInliner { final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null); - final Iterator iterator = anonymousObjectGenerations.iterator(); + final Iterator iterator = anonymousObjectRegenerations.iterator(); final TypeRemapper remapper = TypeRemapper.createFrom(currentTypeMapping); final RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter( @@ -173,8 +173,8 @@ public class MethodInliner { final int markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node); InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.getArgsSizeOnStack(), sourceMapper) { - private AnonymousObjectGeneration anonymousObjectGen; - private void handleAnonymousObjectGeneration() { + private AnonymousObjectRegenerationInfo anonymousObjectGen; + private void handleAnonymousObjectRegeneration() { anonymousObjectGen = iterator.next(); if (anonymousObjectGen.shouldRegenerate(isSameModule)) { @@ -183,7 +183,7 @@ public class MethodInliner { String newClassName = inliningContext.nameGenerator.genLambdaClassName(); remapper.addMapping(oldClassName, newClassName); AnonymousObjectTransformer transformer = - new AnonymousObjectTransformer(oldClassName, + new AnonymousObjectTransformer((AnonymousObjectRegenerationInfo) anonymousObjectGen, inliningContext .subInlineWithClassRegeneration( inliningContext.nameGenerator, @@ -213,7 +213,7 @@ public class MethodInliner { @Override public void anew(@NotNull Type type) { if (isAnonymousConstructorCall(type.getInternalName(), "")) { - handleAnonymousObjectGeneration(); + handleAnonymousObjectRegeneration(); } //in case of regenerated anonymousObjectGen type would be remapped to new one via remappingMethodAdapter @@ -278,7 +278,7 @@ public class MethodInliner { visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(), "$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor()); } - String newInternalName = anonymousObjectGen.getNewLambdaType().getInternalName(); + String newInternalName = anonymousObjectGen.getNewClassName(); super.visitMethodInsn(opcode, newInternalName, name, anonymousObjectGen.getNewConstructorDescriptor(), itf); //TODO: add new inner class also for other contexts @@ -302,7 +302,7 @@ public class MethodInliner { @Override public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) { if (opcode == Opcodes.GETSTATIC && isAnonymousSingletonLoad(owner, name)) { - handleAnonymousObjectGeneration(); + handleAnonymousObjectRegeneration(); } super.visitFieldInsn(opcode, owner, name, desc); } @@ -488,7 +488,7 @@ public class MethodInliner { offset += i == 0 ? 1 : argTypes[i - 1].getSize(); } - anonymousObjectGenerations.add( + anonymousObjectRegenerations.add( buildConstructorInvocation( owner, desc, lambdaMapping, awaitClassReification ) @@ -500,8 +500,8 @@ public class MethodInliner { FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; String owner = fieldInsnNode.owner; if (isAnonymousSingletonLoad(owner, fieldInsnNode.name)) { - anonymousObjectGenerations.add( - new AnonymousObjectGeneration( + anonymousObjectRegenerations.add( + new AnonymousObjectRegenerationInfo( owner, awaitClassReification, isAlreadyRegenerated(owner), true ) ); @@ -551,13 +551,13 @@ public class MethodInliner { } @NotNull - private AnonymousObjectGeneration buildConstructorInvocation( + private AnonymousObjectRegenerationInfo buildConstructorInvocation( @NotNull String anonymousType, @NotNull String desc, @NotNull Map lambdaMapping, boolean needReification ) { - return new AnonymousObjectGeneration( + return new AnonymousObjectRegenerationInfo( anonymousType, needReification, lambdaMapping, inliningContext.classRegeneration, isAlreadyRegenerated(anonymousType), diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ObjectTransformer.kt new file mode 100644 index 00000000000..ea878223078 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ObjectTransformer.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2016 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.kotlin.codegen.inline + +import org.jetbrains.kotlin.codegen.ClassBuilder +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.org.objectweb.asm.ClassReader +import org.jetbrains.org.objectweb.asm.ClassVisitor +import org.jetbrains.org.objectweb.asm.Type + +abstract class ObjectTransformer(val regenerationInfo: T, val state: GenerationState) { + + abstract fun doTransform(info: T, parentRemapper: FieldRemapper): InlineResult + + @JvmField + val transformationResult = InlineResult.create() + + protected fun createRemappingClassBuilderViaFactory(inliningContext: InliningContext): ClassBuilder { + val classBuilder = state.factory.newVisitor( + JvmDeclarationOrigin.NO_ORIGIN, + Type.getObjectType(regenerationInfo.getNewClassName()), + inliningContext.root.callElement.containingFile + ) + + return RemappingClassBuilder( + classBuilder, + AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.root.typeParameterMappings == null, transformationResult)) + } + + + fun createClassReader(): ClassReader { + return InlineCodegenUtil.buildClassReaderByInternalName(state, regenerationInfo.getOldClassName()) + } + +} + +class WhenMappingTransformer( + whenObjectRegenerationInfo: WhenMappingRegenerationInfo, + state: GenerationState, + val inliningContext: InliningContext +) : ObjectTransformer(whenObjectRegenerationInfo, state) { + + override fun doTransform(info: WhenMappingRegenerationInfo, parentRemapper: FieldRemapper): InlineResult { + val classReader = createClassReader() + //TODO add additional check that it's when mapping + + val classBuilder = createRemappingClassBuilderViaFactory(inliningContext) + classReader.accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) { + override fun visit(version: Int, access: Int, name: String, signature: String, superName: String, interfaces: Array) { + InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name) + super.visit(version, access, name, signature, superName, interfaces) + } + }, ClassReader.SKIP_FRAMES) + + return transformationResult + } +} + diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegenerationInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegenerationInfo.kt new file mode 100644 index 00000000000..47ea304ffac --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/RegenerationInfo.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2016 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.kotlin.codegen.inline + +abstract class RegenerationInfo() { + + abstract fun getOldClassName(): String + abstract fun getNewClassName(): String + + abstract fun shouldRegenerate(sameModule: Boolean): Boolean + +} + +class WhenMappingRegenerationInfo(val oldName: String, val nameGenerator: NameGenerator) : RegenerationInfo() { + + override fun shouldRegenerate(sameModule: Boolean): Boolean { + throw UnsupportedOperationException() + } + + override fun getOldClassName(): String { + return oldName + } + + override fun getNewClassName(): String { + return nameGenerator.genLambdaClassName() + oldName + } +} \ No newline at end of file