Fix for KT-7017: Reified type referenced in object literal crashes at runtime

#KT-7017 Fixed
This commit is contained in:
Michael Bogdanov
2015-10-22 14:14:01 +03:00
parent 3e19514099
commit a7b3c70d21
5 changed files with 59 additions and 28 deletions
@@ -43,6 +43,8 @@ public class AnonymousObjectTransformer {
protected final JetTypeMapper typeMapper; protected final JetTypeMapper typeMapper;
private final InlineResult transformationResult;
private MethodNode constructor; private MethodNode constructor;
private String sourceInfo; private String sourceInfo;
@@ -80,6 +82,7 @@ public class AnonymousObjectTransformer {
reader = InlineCodegenUtil.buildClassReaderByInternalName(state, objectInternalName); reader = InlineCodegenUtil.buildClassReaderByInternalName(state, objectInternalName);
typeRemapper = new TypeRemapper(inliningContext.typeMapping); typeRemapper = new TypeRemapper(inliningContext.typeMapping);
transformationResult = InlineResult.create();
} }
@NotNull @NotNull
@@ -87,14 +90,13 @@ public class AnonymousObjectTransformer {
ClassBuilder classBuilder = createClassBuilder(); ClassBuilder classBuilder = createClassBuilder();
final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>(); final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();
final InlineResult result = InlineResult.create();
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
@Override @Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
if (signature != null) { if (signature != null) {
ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature); ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature);
signature = signatureResult.getNewSignature(); signature = signatureResult.getNewSignature();
result.getReifiedTypeParametersUsages().mergeAll(signatureResult.getTypeParametersUsages()); transformationResult.getReifiedTypeParametersUsages().mergeAll(signatureResult.getTypeParametersUsages());
} }
super.visit(version, access, name, signature, superName, interfaces); super.visit(version, access, name, signature, superName, interfaces);
} }
@@ -182,9 +184,8 @@ public class AnonymousObjectTransformer {
for (MethodNode next : methodsToTransform) { for (MethodNode next : methodsToTransform) {
MethodVisitor deferringVisitor = newMethod(classBuilder, next); MethodVisitor deferringVisitor = newMethod(classBuilder, next);
InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder); InlineResult funResult =
result.addAllClassesToRemove(funResult); inlineMethodAndUpdateGlobalResult(anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false);
result.getReifiedTypeParametersUsages().mergeAll(funResult.getReifiedTypeParametersUsages());
Type returnType = Type.getReturnType(next.desc); Type returnType = Type.getReturnType(next.desc);
if (!AsmUtil.isPrimitive(returnType)) { if (!AsmUtil.isPrimitive(returnType)) {
@@ -201,17 +202,29 @@ public class AnonymousObjectTransformer {
method.visitEnd(); method.visitEnd();
} }
InlineResult constructorResult = generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams);
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams);
result.addAllClassesToRemove(constructorResult);
SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder);
classBuilder.done(); classBuilder.done();
anonymousObjectGen.setNewLambdaType(newLambdaType); anonymousObjectGen.setNewLambdaType(newLambdaType);
return result; return transformationResult;
}
@NotNull
private InlineResult inlineMethodAndUpdateGlobalResult(
@NotNull AnonymousObjectGeneration anonymousObjectGen,
@NotNull FieldRemapper parentRemapper,
@NotNull MethodVisitor deferringVisitor,
@NotNull MethodNode next,
@NotNull ParametersBuilder allCapturedParamBuilder,
boolean isConstructor
) {
InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, isConstructor);
transformationResult.addAllClassesToRemove(funResult);
transformationResult.getReifiedTypeParametersUsages().mergeAll(funResult.getReifiedTypeParametersUsages());
return funResult;
} }
@NotNull @NotNull
@@ -220,15 +233,16 @@ public class AnonymousObjectTransformer {
@NotNull FieldRemapper parentRemapper, @NotNull FieldRemapper parentRemapper,
@NotNull MethodVisitor deferringVisitor, @NotNull MethodVisitor deferringVisitor,
@NotNull MethodNode sourceNode, @NotNull MethodNode sourceNode,
@NotNull ParametersBuilder capturedBuilder @NotNull ParametersBuilder capturedBuilder,
boolean isConstructor
) { ) {
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions); ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions);
Parameters parameters = getMethodParametersWithCaptured(capturedBuilder, sourceNode); Parameters parameters = isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode);
RegeneratedLambdaFieldRemapper remapper = RegeneratedLambdaFieldRemapper remapper =
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(), new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
parameters, anonymousObjectGen.getCapturedLambdasToInline(), parameters, anonymousObjectGen.getCapturedLambdasToInline(),
parentRemapper, false); parentRemapper, isConstructor);
MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName(), remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName(),
@@ -240,7 +254,7 @@ public class AnonymousObjectTransformer {
return result; return result;
} }
private InlineResult generateConstructorAndFields( private void generateConstructorAndFields(
@NotNull ClassBuilder classBuilder, @NotNull ClassBuilder classBuilder,
@NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder allCapturedBuilder,
@NotNull ParametersBuilder constructorInlineBuilder, @NotNull ParametersBuilder constructorInlineBuilder,
@@ -311,25 +325,12 @@ public class AnonymousObjectTransformer {
} }
} }
Parameters constructorParameters = constructorInlineBuilder.buildParameters(); inlineMethodAndUpdateGlobalResult(anonymousObjectGen, parentRemapper, capturedFieldInitializer, constructor, constructorInlineBuilder, true);
RegeneratedLambdaFieldRemapper remapper =
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
constructorParameters, anonymousObjectGen.getCapturedLambdasToInline(),
parentRemapper, true);
MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for constructor of " + anonymousObjectGen.getOwnerInternalName(),
sourceMapper);
InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false,
LabelOwner.NOT_APPLICABLE);
constructorVisitor.visitMaxs(-1, -1);
constructorVisitor.visitEnd(); constructorVisitor.visitEnd();
AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder); AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder);
//TODO for inline method make public class //TODO for inline method make public class
anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor); anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor);
return result;
} }
@NotNull @NotNull
@@ -0,0 +1,9 @@
import test.*
fun box(): String {
if (!test<String>("OK")) return "fail 1"
if (test<Int>("OK")) return "fail 2"
return "OK"
}
@@ -0,0 +1,9 @@
package test
inline fun test<reified T>(x: Any): Boolean {
val x = object {
val y = x is T
}
return x.y
}
@@ -1084,6 +1084,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
doTestMultiFileWithInlineCheck(fileName); doTestMultiFileWithInlineCheck(fileName);
} }
@TestMetadata("kt7017.1.kt")
public void testKt7017() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt7017.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("packages.1.kt") @TestMetadata("packages.1.kt")
public void testPackages() throws Exception { public void testPackages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
@@ -1084,6 +1084,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doBoxTestWithInlineCheck(fileName); doBoxTestWithInlineCheck(fileName);
} }
@TestMetadata("kt7017.1.kt")
public void testKt7017() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt7017.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("packages.1.kt") @TestMetadata("packages.1.kt")
public void testPackages() throws Exception { public void testPackages() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");