diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index 99de43e10c1..d8100f0b12a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -14,420 +14,392 @@ * limitations under the License. */ -package org.jetbrains.kotlin.codegen.inline; +package org.jetbrains.kotlin.codegen.inline -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.codegen.AsmUtil; -import org.jetbrains.kotlin.codegen.ClassBuilder; -import org.jetbrains.kotlin.codegen.FieldInfo; -import org.jetbrains.kotlin.codegen.StackValue; -import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; -import org.jetbrains.org.objectweb.asm.*; -import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; -import org.jetbrains.org.objectweb.asm.tree.*; +import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.ClassBuilder +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE +import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.isThis0 +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN +import org.jetbrains.org.objectweb.asm.* +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.tree.* +import java.util.* -import java.util.*; +class AnonymousObjectTransformer( + transformationInfo: AnonymousObjectTransformationInfo, + private val inliningContext: InliningContext, + private val isSameModule: Boolean +) : ObjectTransformer(transformationInfo, inliningContext.state) { -import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.isThis0; -import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; + private val oldObjectType = Type.getObjectType(transformationInfo.oldClassName) -public class AnonymousObjectTransformer extends ObjectTransformer { - private final InliningContext inliningContext; - private final Type oldObjectType; - private final boolean isSameModule; - private final Map> fieldNames = new HashMap<>(); + private val fieldNames = hashMapOf>() - private MethodNode constructor; - private String sourceInfo; - private String debugInfo; - private SourceMapper sourceMapper; + private var constructor: MethodNode? = null + private var sourceInfo: String? = null + private var debugInfo: String? = null + private var sourceMapper: SourceMapper? = null - public AnonymousObjectTransformer( - @NotNull AnonymousObjectTransformationInfo transformationInfo, - @NotNull InliningContext inliningContext, - boolean isSameModule - ) { - super(transformationInfo, inliningContext.state); - this.isSameModule = isSameModule; - this.inliningContext = inliningContext; - this.oldObjectType = Type.getObjectType(transformationInfo.getOldClassName()); - } + override fun doTransform(parentRemapper: FieldRemapper): InlineResult { + val innerClassNodes = ArrayList() + val classBuilder = createRemappingClassBuilderViaFactory(inliningContext) + val methodsToTransform = ArrayList() - @Override - @NotNull - public InlineResult doTransform(@NotNull FieldRemapper parentRemapper) { - List innerClassNodes = new ArrayList<>(); - ClassBuilder classBuilder = createRemappingClassBuilderViaFactory(inliningContext); - List methodsToTransform = new ArrayList<>(); - - 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) { - classBuilder.defineClass(null, version, access, name, signature, superName, interfaces); - if(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE.getInternalName().equals(superName)) { - inliningContext.setContinuation(true); + createClassReader().accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) { + override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array) { + classBuilder.defineClass(null, version, access, name, signature, superName, interfaces) + if (COROUTINE_IMPL_ASM_TYPE.internalName == superName) { + inliningContext.isContinuation = true } } - @Override - public void visitInnerClass(@NotNull String name, String outerName, String innerName, int access) { - innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access)); + override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) { + innerClassNodes.add(InnerClassNode(name, outerName, innerName, access)) } - @Override - public MethodVisitor visitMethod( - int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions - ) { - MethodNode node = new MethodNode(access, name, desc, signature, exceptions); - if (name.equals("")) { + override fun visitMethod( + access: Int, name: String, desc: String, signature: String?, exceptions: Array? + ): MethodVisitor { + val node = MethodNode(access, name, desc, signature, exceptions) + if (name == "") { if (constructor != null) { - throw new RuntimeException("Lambda, SAM or anonymous object should have only one constructor"); + throw RuntimeException("Lambda, SAM or anonymous object should have only one constructor") } - constructor = node; + constructor = node } else { - methodsToTransform.add(node); + methodsToTransform.add(node) } - return node; + return node } - @Override - public FieldVisitor visitField(int access, @NotNull String name, @NotNull String desc, String signature, Object value) { - addUniqueField(name); + override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? { + addUniqueField(name) if (InlineCodegenUtil.isCapturedFieldName(name)) { - return null; + return null } else { - return classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, value); + return classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, value) } } - @Override - public void visitSource(String source, String debug) { - sourceInfo = source; - debugInfo = debug; + override fun visitSource(source: String, debug: String?) { + sourceInfo = source + debugInfo = debug } - @Override - public void visitEnd() { - } - }, ClassReader.SKIP_FRAMES); + override fun visitEnd() {} + }, ClassReader.SKIP_FRAMES) if (!inliningContext.isInliningLambda) { - if (debugInfo != null && !debugInfo.isEmpty()) { - sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo)); + if (debugInfo != null && !debugInfo!!.isEmpty()) { + sourceMapper = SourceMapper.createFromSmap(SMAPParser.parse(debugInfo!!)) } else { //seems we can't do any clever mapping cause we don't know any about original class name - sourceMapper = IdenticalSourceMapper.INSTANCE; + sourceMapper = IdenticalSourceMapper } if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) { - classBuilder.visitSource(sourceInfo, debugInfo); + classBuilder.visitSource(sourceInfo!!, debugInfo) } } else { if (sourceInfo != null) { - classBuilder.visitSource(sourceInfo, debugInfo); + classBuilder.visitSource(sourceInfo!!, debugInfo) } - sourceMapper = IdenticalSourceMapper.INSTANCE; + sourceMapper = IdenticalSourceMapper } - ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); - ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); - List additionalFakeParams = - extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, - transformationInfo, parentRemapper); - List deferringMethods = new ArrayList<>(); + val allCapturedParamBuilder = ParametersBuilder.newBuilder() + val constructorParamBuilder = ParametersBuilder.newBuilder() + val additionalFakeParams = extractParametersMappingAndPatchConstructor( + constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper + ) + val deferringMethods = ArrayList() - generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams); + generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams) - for (MethodNode next : methodsToTransform) { - DeferredMethodVisitor deferringVisitor = newMethod(classBuilder, next); - InlineResult funResult = - inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); + for (next in methodsToTransform) { + val deferringVisitor = newMethod(classBuilder, next) + val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false) - Type returnType = Type.getReturnType(next.desc); + val returnType = Type.getReturnType(next.desc) if (!AsmUtil.isPrimitive(returnType)) { - String oldFunReturnType = returnType.getInternalName(); - String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType); + val oldFunReturnType = returnType.internalName + val newFunReturnType = funResult.getChangedTypes()[oldFunReturnType] if (newFunReturnType != null) { - inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType); + inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType) } } - deferringMethods.add(deferringVisitor); + deferringMethods.add(deferringVisitor) } - for (DeferredMethodVisitor method : deferringMethods) { - InlineCodegenUtil.removeFinallyMarkers(method.getIntermediate()); - method.visitEnd(); + deferringMethods.forEach { method -> + InlineCodegenUtil.removeFinallyMarkers(method.intermediate) + method.visitEnd() } - SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); + SourceMapper.flushToClassBuilder(sourceMapper!!, classBuilder) - ClassVisitor visitor = classBuilder.getVisitor(); - for (InnerClassNode node : innerClassNodes) { - visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access); + val visitor = classBuilder.visitor + innerClassNodes.forEach { + node -> visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access) } - writeOuterInfo(visitor); + writeOuterInfo(visitor) - classBuilder.done(); + classBuilder.done() - return transformationResult; + return transformationResult } - private void writeOuterInfo(@NotNull ClassVisitor visitor) { - InlineCallSiteInfo info = inliningContext.getCallSiteInfo(); - visitor.visitOuterClass(info.getOwnerClassName(), info.getFunctionName(), info.getFunctionDesc()); + private fun writeOuterInfo(visitor: ClassVisitor) { + val info = inliningContext.callSiteInfo + visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc) } - @NotNull - private InlineResult inlineMethodAndUpdateGlobalResult( - @NotNull FieldRemapper parentRemapper, - @NotNull MethodVisitor deferringVisitor, - @NotNull MethodNode next, - @NotNull ParametersBuilder allCapturedParamBuilder, - boolean isConstructor - ) { - InlineResult funResult = inlineMethod(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor); - transformationResult.merge(funResult); - transformationResult.getReifiedTypeParametersUsages().mergeAll(funResult.getReifiedTypeParametersUsages()); - return funResult; + private fun inlineMethodAndUpdateGlobalResult( + parentRemapper: FieldRemapper, + deferringVisitor: MethodVisitor, + next: MethodNode, + allCapturedParamBuilder: ParametersBuilder, + isConstructor: Boolean + ): InlineResult { + val funResult = inlineMethod(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor) + transformationResult.merge(funResult) + transformationResult.reifiedTypeParametersUsages.mergeAll(funResult.reifiedTypeParametersUsages) + return funResult } - @NotNull - private InlineResult inlineMethod( - @NotNull FieldRemapper parentRemapper, - @NotNull MethodVisitor deferringVisitor, - @NotNull MethodNode sourceNode, - @NotNull ParametersBuilder capturedBuilder, - boolean isConstructor - ) { - ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifiedTypeInliner.reifyInstructions(sourceNode); - Parameters parameters = - isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode); + private fun inlineMethod( + parentRemapper: FieldRemapper, + deferringVisitor: MethodVisitor, + sourceNode: MethodNode, + capturedBuilder: ParametersBuilder, + isConstructor: Boolean + ): InlineResult { + val typeParametersToReify = inliningContext.reifiedTypeInliner.reifyInstructions(sourceNode) + val parameters = if (isConstructor) capturedBuilder.buildParameters() else getMethodParametersWithCaptured(capturedBuilder, sourceNode) - RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper( - oldObjectType.getInternalName(), transformationInfo.getNewClassName(), parameters, - transformationInfo.getCapturedLambdasToInline(), parentRemapper, isConstructor - ); + val remapper = RegeneratedLambdaFieldRemapper( + oldObjectType.internalName, transformationInfo.newClassName, parameters, + transformationInfo.capturedLambdasToInline, parentRemapper, isConstructor + ) - MethodInliner inliner = new MethodInliner( + val inliner = MethodInliner( sourceNode, parameters, - inliningContext.subInline(transformationInfo.getNameGenerator()), + inliningContext.subInline(transformationInfo.nameGenerator), remapper, isSameModule, - "Transformer for " + transformationInfo.getOldClassName(), - sourceMapper, - new InlineCallSiteInfo( - transformationInfo.getOldClassName(), + "Transformer for " + transformationInfo.oldClassName, + sourceMapper!!, + InlineCallSiteInfo( + transformationInfo.oldClassName, sourceNode.name, - isConstructor ? transformationInfo.getNewConstructorDescriptor() : sourceNode.desc - ), - null - ); + if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc + ), null + ) - InlineResult result = inliner.doInline(deferringVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE); - result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify); - deferringVisitor.visitMaxs(-1, -1); - return result; + val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE) + result.reifiedTypeParametersUsages.mergeAll(typeParametersToReify) + deferringVisitor.visitMaxs(-1, -1) + return result } - private void generateConstructorAndFields( - @NotNull ClassBuilder classBuilder, - @NotNull ParametersBuilder allCapturedBuilder, - @NotNull ParametersBuilder constructorInlineBuilder, - @NotNull FieldRemapper parentRemapper, - @NotNull List constructorAdditionalFakeParams + private fun generateConstructorAndFields( + classBuilder: ClassBuilder, + allCapturedBuilder: ParametersBuilder, + constructorInlineBuilder: ParametersBuilder, + parentRemapper: FieldRemapper, + constructorAdditionalFakeParams: List ) { - List descTypes = new ArrayList<>(); + val descTypes = ArrayList() - Parameters constructorParams = constructorInlineBuilder.buildParameters(); - int[] capturedIndexes = new int[constructorParams.getParameters().size()]; - int index = 0; - int size = 0; + val constructorParams = constructorInlineBuilder.buildParameters() + val capturedIndexes = IntArray(constructorParams.parameters.size) + var index = 0 + var size = 0 //complex processing cause it could have super constructor call params - for (ParameterInfo info : constructorParams) { + for (info in constructorParams) { if (!info.isSkipped) { //not inlined - if (info.isCaptured() || info instanceof CapturedParamInfo) { - capturedIndexes[index] = size; - index++; + if (info.isCaptured || info is CapturedParamInfo) { + capturedIndexes[index] = size + index++ } if (size != 0) { //skip this - descTypes.add(info.getType()); + descTypes.add(info.getType()) } - size += info.getType().getSize(); + size += info.getType().size } } - String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()])); + val constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *descTypes.toTypedArray()) //TODO for inline method make public class - transformationInfo.setNewConstructorDescriptor(constructorDescriptor); - MethodVisitor constructorVisitor = classBuilder.newMethod( - NO_ORIGIN, constructor.access, "", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY - ); + transformationInfo.newConstructorDescriptor = constructorDescriptor + val constructorVisitor = classBuilder.newMethod( + NO_ORIGIN, constructor!!.access, "", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY + ) - Label newBodyStartLabel = new Label(); - constructorVisitor.visitLabel(newBodyStartLabel); + val newBodyStartLabel = Label() + constructorVisitor.visitLabel(newBodyStartLabel) //initialize captured fields - List newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured()); - List fieldInfoWithSkipped = - TransformationUtilsKt.transformToFieldInfo(Type.getObjectType(transformationInfo.getNewClassName()), newFieldsWithSkipped); + val newFieldsWithSkipped = getNewFieldsToGenerate(allCapturedBuilder.listCaptured()) + val fieldInfoWithSkipped = transformToFieldInfo(Type.getObjectType(transformationInfo.newClassName), newFieldsWithSkipped) - int paramIndex = 0; - InstructionAdapter capturedFieldInitializer = new InstructionAdapter(constructorVisitor); - for (int i = 0; i < fieldInfoWithSkipped.size(); i++) { - FieldInfo fieldInfo = fieldInfoWithSkipped.get(i); - if (!newFieldsWithSkipped.get(i).getSkip()) { - AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer); + var paramIndex = 0 + val capturedFieldInitializer = InstructionAdapter(constructorVisitor) + for (i in fieldInfoWithSkipped.indices) { + val fieldInfo = fieldInfoWithSkipped[i] + if (!newFieldsWithSkipped[i].skip) { + AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer) } - paramIndex++; + paramIndex++ } //then transform constructor //HACK: in inlinining into constructor we access original captured fields with field access not local var //but this fields added to general params (this assumes local var access) not captured one, //so we need to add them to captured params - for (CapturedParamInfo info : constructorAdditionalFakeParams) { - CapturedParamInfo fake = constructorInlineBuilder.addCapturedParamCopy(info); + for (info in constructorAdditionalFakeParams) { + val fake = constructorInlineBuilder.addCapturedParamCopy(info) - if (fake.getLambda() != null) { + if (fake.lambda != null) { //set remap value to skip this fake (captured with lambda already skipped) - StackValue composed = StackValue.field( + val composed = StackValue.field( fake.getType(), oldObjectType, - fake.getNewFieldName(), + fake.newFieldName, false, StackValue.LOCAL_0 - ); - fake.setRemapValue(composed); + ) + fake.remapValue = composed } } - MethodNode intermediateMethodNode = - new MethodNode(constructor.access, "", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY); - inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true); - InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode); + val intermediateMethodNode = MethodNode(constructor!!.access, "", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY) + inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor!!, constructorInlineBuilder, true) + InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode) - AbstractInsnNode first = intermediateMethodNode.instructions.getFirst(); - Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null; - intermediateMethodNode.accept(new MethodBodyVisitor(capturedFieldInitializer) { - @Override - public void visitLocalVariable( - @NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index + val first = intermediateMethodNode.instructions.first + val oldStartLabel = if (first is LabelNode) first.label else null + intermediateMethodNode.accept(object : MethodBodyVisitor(capturedFieldInitializer) { + override fun visitLocalVariable( + name: String, desc: String, signature: String?, start: Label, end: Label, index: Int ) { - if (oldStartLabel == start) { - start = newBodyStartLabel;//patch for jack&jill - } - super.visitLocalVariable(name, desc, signature, start, end, index); + super.visitLocalVariable( + name, desc, signature, + //patch for jack&jill + if (oldStartLabel === start) newBodyStartLabel else start, + end, index + ) } - }); - constructorVisitor.visitEnd(); + }) + constructorVisitor.visitEnd() AsmUtil.genClosureFields( - TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder - ); + toNameTypePair(filterSkipped(newFieldsWithSkipped)), classBuilder + ) } - @NotNull - private Parameters getMethodParametersWithCaptured(@NotNull ParametersBuilder capturedBuilder, @NotNull MethodNode sourceNode) { - ParametersBuilder builder = ParametersBuilder.initializeBuilderFrom(oldObjectType, sourceNode.desc); - for (CapturedParamInfo param : capturedBuilder.listCaptured()) { - builder.addCapturedParamCopy(param); + private fun getMethodParametersWithCaptured(capturedBuilder: ParametersBuilder, sourceNode: MethodNode): Parameters { + val builder = ParametersBuilder.initializeBuilderFrom(oldObjectType, sourceNode.desc) + for (param in capturedBuilder.listCaptured()) { + builder.addCapturedParamCopy(param) } - return builder.buildParameters(); + return builder.buildParameters() } - @NotNull - private static DeferredMethodVisitor newMethod(@NotNull ClassBuilder builder, @NotNull MethodNode original) { - return new DeferredMethodVisitor( - new MethodNode( + private fun newMethod(builder: ClassBuilder, original: MethodNode): DeferredMethodVisitor { + return DeferredMethodVisitor( + MethodNode( original.access, original.name, original.desc, original.signature, ArrayUtil.toStringArray(original.exceptions) - ), - () -> builder.newMethod( - NO_ORIGIN, original.access, original.name, original.desc, original.signature, - ArrayUtil.toStringArray(original.exceptions) ) - ); + ) { + builder.newMethod( + NO_ORIGIN, original.access, original.name, original.desc, original.signature, + ArrayUtil.toStringArray(original.exceptions) + ) + } } - @NotNull - private List extractParametersMappingAndPatchConstructor( - @NotNull MethodNode constructor, - @NotNull ParametersBuilder capturedParamBuilder, - @NotNull ParametersBuilder constructorParamBuilder, - @NotNull AnonymousObjectTransformationInfo transformationInfo, - @NotNull FieldRemapper parentFieldRemapper - ) { - Set capturedLambdas = new LinkedHashSet<>(); //captured var of inlined parameter - List constructorAdditionalFakeParams = new ArrayList<>(); - Map indexToLambda = transformationInfo.getLambdasToInline(); - Set capturedParams = new HashSet<>(); + private fun extractParametersMappingAndPatchConstructor( + constructor: MethodNode, + capturedParamBuilder: ParametersBuilder, + constructorParamBuilder: ParametersBuilder, + transformationInfo: AnonymousObjectTransformationInfo, + parentFieldRemapper: FieldRemapper + ): List { + val capturedLambdas = LinkedHashSet() //captured var of inlined parameter + val constructorAdditionalFakeParams = ArrayList() + val indexToLambda = transformationInfo.lambdasToInline + val capturedParams = HashSet() //load captured parameters and patch instruction list (NB: there is also could be object fields) - AbstractInsnNode cur = constructor.instructions.getFirst(); + var cur: AbstractInsnNode? = constructor.instructions.first while (cur != null) { - if (cur instanceof FieldInsnNode) { - FieldInsnNode fieldNode = (FieldInsnNode) cur; - String fieldName = fieldNode.name; - if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldName)) { - boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode; - boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode; + if (cur is FieldInsnNode) { + val fieldNode = cur as FieldInsnNode? + val fieldName = fieldNode!!.name + if (fieldNode.opcode == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldName)) { + val isPrevVarNode = fieldNode.previous is VarInsnNode + val isPrevPrevVarNode = isPrevVarNode && fieldNode.previous.previous is VarInsnNode if (isPrevPrevVarNode) { - VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious(); - if (node.var == 0) { - VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious(); - int varIndex = previous.var; - LambdaInfo lambdaInfo = indexToLambda.get(varIndex); - String newFieldName = - isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values()) - ? getNewFieldName(fieldName, true) - : fieldName; - CapturedParamInfo info = capturedParamBuilder.addCapturedParam( - Type.getObjectType(transformationInfo.getOldClassName()), fieldName, newFieldName, + val node = fieldNode.previous.previous as VarInsnNode + if (node.`var` == 0) { + val previous = fieldNode.previous as VarInsnNode + val varIndex = previous.`var` + val lambdaInfo = indexToLambda[varIndex] + val newFieldName = if (isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values)) + getNewFieldName(fieldName, true) + else + fieldName + val info = capturedParamBuilder.addCapturedParam( + Type.getObjectType(transformationInfo.oldClassName), fieldName, newFieldName, Type.getType(fieldNode.desc), lambdaInfo != null, null - ); + ) if (lambdaInfo != null) { - info.setLambda(lambdaInfo); - capturedLambdas.add(lambdaInfo); + info.lambda = lambdaInfo + capturedLambdas.add(lambdaInfo) } - constructorAdditionalFakeParams.add(info); - capturedParams.add(varIndex); + constructorAdditionalFakeParams.add(info) + capturedParams.add(varIndex) - constructor.instructions.remove(previous.getPrevious()); - constructor.instructions.remove(previous); - AbstractInsnNode temp = cur; - cur = cur.getNext(); - constructor.instructions.remove(temp); - continue; + constructor.instructions.remove(previous.previous) + constructor.instructions.remove(previous) + val temp = cur + cur = cur.next + constructor.instructions.remove(temp) + continue } } } } - cur = cur.getNext(); + cur = cur.next } - constructorParamBuilder.addThis(oldObjectType, false); - String constructorDesc = transformationInfo.getConstructorDesc(); + constructorParamBuilder.addThis(oldObjectType, false) + var constructorDesc = transformationInfo.constructorDesc if (constructorDesc == null) { // in case of anonymous object with empty closure - constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE); + constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE) } - Type[] types = Type.getArgumentTypes(constructorDesc); - for (Type type : types) { - LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextParameterOffset()); - ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null); - parameterInfo.setLambda(info); - if (capturedParams.contains(parameterInfo.getIndex())) { - parameterInfo.setCaptured(true); + val types = Type.getArgumentTypes(constructorDesc!!) + for (type in types) { + val info = indexToLambda[constructorParamBuilder.nextParameterOffset] + val parameterInfo = constructorParamBuilder.addNextParameter(type, info != null) + parameterInfo.lambda = info + if (capturedParams.contains(parameterInfo.index)) { + parameterInfo.isCaptured = true } else { //otherwise it's super constructor parameter @@ -436,102 +408,96 @@ public class AnonymousObjectTransformer extends ObjectTransformer capturedLambdasToInline = new HashMap<>(); //captured var of inlined parameter - List allRecapturedParameters = new ArrayList<>(); - boolean addCapturedNotAddOuter = - parentFieldRemapper.isRoot() || - (parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot()); - Map alreadyAdded = new HashMap<>(); - for (LambdaInfo info : capturedLambdas) { + val capturedLambdasToInline = HashMap() //captured var of inlined parameter + val allRecapturedParameters = ArrayList() + val addCapturedNotAddOuter = parentFieldRemapper.isRoot || parentFieldRemapper is InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot + val alreadyAdded = HashMap() + for (info in capturedLambdas) { if (addCapturedNotAddOuter) { - for (CapturedParamDesc desc : info.getCapturedVars()) { - String key = desc.getFieldName() + "$$$" + desc.getType().getClassName(); - CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key); + for (desc in info.capturedVars) { + val key = desc.fieldName + "$$$" + desc.type.className + val alreadyAddedParam = alreadyAdded[key] - CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam( + val recapturedParamInfo = capturedParamBuilder.addCapturedParam( desc, - alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false), + alreadyAddedParam?.newFieldName ?: getNewFieldName(desc.fieldName, false), alreadyAddedParam != null - ); - StackValue composed = StackValue.field( - desc.getType(), + ) + val composed = StackValue.field( + desc.type, oldObjectType, /*TODO owner type*/ - recapturedParamInfo.getNewFieldName(), + recapturedParamInfo.newFieldName, false, StackValue.LOCAL_0 - ); - recapturedParamInfo.setRemapValue(composed); - allRecapturedParameters.add(desc); + ) + recapturedParamInfo.remapValue = composed + allRecapturedParameters.add(desc) - constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()) - .setRemapValue(composed); + constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue = composed - if (isThis0(desc.getFieldName())) { - alreadyAdded.put(key, recapturedParamInfo); + if (isThis0(desc.fieldName)) { + alreadyAdded.put(key, recapturedParamInfo) } } } - capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info); + capturedLambdasToInline.put(info.lambdaClassType.internalName, info) } - if (parentFieldRemapper instanceof InlinedLambdaRemapper && !capturedLambdas.isEmpty() && !addCapturedNotAddOuter) { + if (parentFieldRemapper is InlinedLambdaRemapper && !capturedLambdas.isEmpty() && !addCapturedNotAddOuter) { //lambda with non InlinedLambdaRemapper already have outer - FieldRemapper parent = parentFieldRemapper.getParent(); - assert parent instanceof RegeneratedLambdaFieldRemapper; - Type ownerType = Type.getObjectType(parent.getLambdaInternalName()); - CapturedParamDesc desc = new CapturedParamDesc(ownerType, InlineCodegenUtil.THIS, ownerType); - CapturedParamInfo recapturedParamInfo = - capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.THIS$0/*outer lambda/object*/, false); - StackValue composed = StackValue.LOCAL_0; - recapturedParamInfo.setRemapValue(composed); - allRecapturedParameters.add(desc); + val parent = parentFieldRemapper.getParent() + assert(parent is RegeneratedLambdaFieldRemapper) + val ownerType = Type.getObjectType(parent.lambdaInternalName) + val desc = CapturedParamDesc(ownerType, InlineCodegenUtil.THIS, ownerType) + val recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.`THIS$0`/*outer lambda/object*/, false) + val composed = StackValue.LOCAL_0 + recapturedParamInfo.remapValue = composed + allRecapturedParameters.add(desc) - constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed); + constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue = composed } - transformationInfo.setAllRecapturedParameters(allRecapturedParameters); - transformationInfo.setCapturedLambdasToInline(capturedLambdasToInline); + transformationInfo.allRecapturedParameters = allRecapturedParameters + transformationInfo.capturedLambdasToInline = capturedLambdasToInline - return constructorAdditionalFakeParams; + return constructorAdditionalFakeParams } - private static boolean shouldRenameThis0(@NotNull FieldRemapper parentFieldRemapper, @NotNull Collection values) { + private fun shouldRenameThis0(parentFieldRemapper: FieldRemapper, values: Collection): Boolean { if (isFirstDeclSiteLambdaFieldRemapper(parentFieldRemapper)) { - for (LambdaInfo value : values) { - for (CapturedParamDesc desc : value.getCapturedVars()) { - if (isThis0(desc.getFieldName())) { - return true; + for (value in values) { + for (desc in value.capturedVars) { + if (isThis0(desc.fieldName)) { + return true } } } } - return false; + return false } - @NotNull - private String getNewFieldName(@NotNull String oldName, boolean originalField) { - if (InlineCodegenUtil.THIS$0.equals(oldName)) { + private fun getNewFieldName(oldName: String, originalField: Boolean): String { + if (InlineCodegenUtil.`THIS$0` == oldName) { if (!originalField) { - return oldName; + return oldName } else { //rename original 'this$0' in declaration site lambda (inside inline function) to use this$0 only for outer lambda/object access on call site - return addUniqueField(oldName + InlineCodegenUtil.INLINE_FUN_THIS_0_SUFFIX); + return addUniqueField(oldName + InlineCodegenUtil.INLINE_FUN_THIS_0_SUFFIX) } } - return addUniqueField(oldName + InlineCodegenUtil.INLINE_TRANSFORMATION_SUFFIX); + return addUniqueField(oldName + InlineCodegenUtil.INLINE_TRANSFORMATION_SUFFIX) } - @NotNull - private String addUniqueField(@NotNull String name) { - List existNames = fieldNames.computeIfAbsent(name, unused -> new LinkedList<>()); - String suffix = existNames.isEmpty() ? "" : "$" + existNames.size(); - String newName = name + suffix; - existNames.add(newName); - return newName; + private fun addUniqueField(name: String): String { + val existNames = fieldNames.getOrPut(name) { LinkedList() } + val suffix = if (existNames.isEmpty()) "" else "$" + existNames.size + val newName = name + suffix + existNames.add(newName) + return newName } - private static boolean isFirstDeclSiteLambdaFieldRemapper(@NotNull FieldRemapper parentRemapper) { - return !(parentRemapper instanceof RegeneratedLambdaFieldRemapper) && !(parentRemapper instanceof InlinedLambdaRemapper); + private fun isFirstDeclSiteLambdaFieldRemapper(parentRemapper: FieldRemapper): Boolean { + return parentRemapper !is RegeneratedLambdaFieldRemapper && parentRemapper !is InlinedLambdaRemapper } }