Fix duplicate field error on inlining several lambdas

This commit is contained in:
Michael Bogdanov
2015-11-24 11:16:08 +03:00
parent d3f7e9f74b
commit a19bdaeb23
4 changed files with 79 additions and 23 deletions
@@ -449,14 +449,6 @@ public class AsmUtil {
}
}
public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) {
List<FieldInfo> result = new ArrayList<FieldInfo>();
for (Pair<String, Type> 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();
@@ -285,26 +285,23 @@ public class AnonymousObjectTransformer {
}
}
List<Pair<String, Type>> capturedFieldsToGenerate = new ArrayList<Pair<String, Type>>();
for (CapturedParamInfo capturedParamInfo : allCapturedBuilder.listCaptured()) {
if (capturedParamInfo.getLambda() == null) { //not inlined
capturedFieldsToGenerate.add(new Pair<String, Type>(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,
"<init>", constructorDescriptor,
null, ArrayUtil.EMPTY_STRING_ARRAY);
//initialize captured fields
List<FieldInfo> fields = AsmUtil.transformCapturedParams(capturedFieldsToGenerate, newLambdaType);
List<NewJavaField> newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured());
List<FieldInfo> 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<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
Set<LambdaInfo> capturedLambdas = new LinkedHashSet<LambdaInfo>(); //captured var of inlined parameter
List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>();
Map<Integer, LambdaInfo> indexToLambda = anonymousObjectGen.getLambdasToInline();
Set<Integer> capturedParams = new HashSet<Integer>();
@@ -459,10 +455,16 @@ public class AnonymousObjectTransformer {
Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter
List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>();
boolean addCapturedNotAddOuter = parentFieldRemapper.isRoot() || (parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot());
Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>();
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);
@@ -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;
}
}
@@ -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<CapturedParamInfo>): List<NewJavaField> {
return params.filter {
//not inlined
it.lambda == null
}.map {
NewJavaField(it.newFieldName, it.type, it.isSkipInConstructor)
}
}
fun transformToFieldInfo(lambdaType: Type, newFields: List<NewJavaField>): List<FieldInfo> {
return newFields.map { field ->
FieldInfo.createForHiddenField(lambdaType, field.type, field.name)
}
}
fun filterSkipped(fields: List<NewJavaField>): List<NewJavaField> {
return fields.filter { !it.skip }
}
fun toNameTypePair(fields: List<NewJavaField>): List<Pair<String, Type>> = fields.map { Pair(it.name, it.type) }