diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 7a421644f0c..156e21bd0d0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -449,14 +449,6 @@ public class AsmUtil { } } - public static List transformCapturedParams(List> allFields, Type owner) { - List result = new ArrayList(); - for (Pair field : allFields) { - result.add(FieldInfo.createForHiddenField(owner, field.second, field.first)); - } - return result; - } - public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) { assert !info.isStatic(); Type fieldType = info.getFieldType(); 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 4f43789ef85..f6afb67f1cf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.java @@ -285,26 +285,23 @@ public class AnonymousObjectTransformer { } } - List> capturedFieldsToGenerate = new ArrayList>(); - for (CapturedParamInfo capturedParamInfo : allCapturedBuilder.listCaptured()) { - if (capturedParamInfo.getLambda() == null) { //not inlined - capturedFieldsToGenerate.add(new Pair(capturedParamInfo.getNewFieldName(), capturedParamInfo.getType())); - } - } - String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()])); - MethodVisitor constructorVisitor = classBuilder.newMethod(NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY); //initialize captured fields - List fields = AsmUtil.transformCapturedParams(capturedFieldsToGenerate, newLambdaType); + List newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured()); + List fieldInfoWithSkipped = TransformationUtilsKt.transformToFieldInfo(newLambdaType, newFieldsWithSkipped); + int paramIndex = 0; InstructionAdapter capturedFieldInitializer = new InstructionAdapter(constructorVisitor); - for (FieldInfo fieldInfo : fields) { - AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer); + for (int i = 0; i < fieldInfoWithSkipped.size(); i++) { + FieldInfo fieldInfo = fieldInfoWithSkipped.get(i); + if (!newFieldsWithSkipped.get(i).getSkip()) { + AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer); + } paramIndex++; } @@ -328,8 +325,7 @@ public class AnonymousObjectTransformer { inlineMethodAndUpdateGlobalResult(anonymousObjectGen, parentRemapper, capturedFieldInitializer, constructor, constructorInlineBuilder, true); constructorVisitor.visitEnd(); - - AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder); + AsmUtil.genClosureFields(TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder); //TODO for inline method make public class anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor); } @@ -390,7 +386,7 @@ public class AnonymousObjectTransformer { } }; - List capturedLambdas = new ArrayList(); //captured var of inlined parameter + Set capturedLambdas = new LinkedHashSet(); //captured var of inlined parameter List constructorAdditionalFakeParams = new ArrayList(); Map indexToLambda = anonymousObjectGen.getLambdasToInline(); Set capturedParams = new HashSet(); @@ -459,10 +455,16 @@ public class AnonymousObjectTransformer { Map 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) { if (addCapturedNotAddOuter) { for (CapturedParamDesc desc : info.getCapturedVars()) { - CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, getNewFieldName(desc.getFieldName(), false)); + String key = desc.getFieldName() + "$$$" + desc.getType().getClassName(); + CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key); + + CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam( + desc, + alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false)); StackValue composed = StackValue.field(desc.getType(), oldObjectType, /*TODO owner type*/ recapturedParamInfo.getNewFieldName(), @@ -472,6 +474,13 @@ public class AnonymousObjectTransformer { allRecapturedParameters.add(desc); constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed); + if (alreadyAddedParam != null) { + recapturedParamInfo.setSkipInConstructor(true); + } + + if (isThis0(desc.getFieldName())) { + alreadyAdded.put(key, recapturedParamInfo); + } } } capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java index 8269a11178f..a44fbd0e4a0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CapturedParamInfo.java @@ -33,6 +33,8 @@ public class CapturedParamInfo extends ParameterInfo { private final String newFieldName; + private boolean skipInConstructor; + public CapturedParamInfo(@NotNull CapturedParamDesc desc, boolean skipped, int index, int remapIndex) { this(desc, desc.getFieldName(), skipped, index, remapIndex); } @@ -68,6 +70,7 @@ public class CapturedParamInfo extends ParameterInfo { public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) { CapturedParamInfo capturedParamInfo = new CapturedParamInfo(desc, newFieldName, isSkipped, newIndex, newRamapIndex); capturedParamInfo.setLambda(lambda); + capturedParamInfo.setSkipInConstructor(skipInConstructor); return capturedParamInfo; } @@ -75,4 +78,12 @@ public class CapturedParamInfo extends ParameterInfo { public String getContainingLambdaName() { return desc.getContainingLambdaName(); } + + public boolean isSkipInConstructor() { + return skipInConstructor; + } + + public void setSkipInConstructor(boolean skipInConstructor) { + this.skipInConstructor = skipInConstructor; + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt new file mode 100644 index 00000000000..dd8b2ded9a6 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/transformationUtils.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2015 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 com.intellij.openapi.util.Pair +import org.jetbrains.kotlin.codegen.FieldInfo +import org.jetbrains.org.objectweb.asm.Type + +class NewJavaField(val name: String, val type: Type, val skip: Boolean) + +fun getNewFieldsToGenerate(params: List): List { + return params.filter { + //not inlined + it.lambda == null + }.map { + NewJavaField(it.newFieldName, it.type, it.isSkipInConstructor) + } +} + +fun transformToFieldInfo(lambdaType: Type, newFields: List): List { + return newFields.map { field -> + FieldInfo.createForHiddenField(lambdaType, field.type, field.name) + } +} + +fun filterSkipped(fields: List): List { + return fields.filter { !it.skip } +} + +fun toNameTypePair(fields: List): List> = fields.map { Pair(it.name, it.type) }