diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java index 1c49d7c109d..2f7e32ab0b0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java @@ -36,6 +36,7 @@ public class OptimizationMethodVisitor extends TransformationMethodVisitor { private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] { new CapturedVarsOptimizationMethodTransformer(), new RedundantNullCheckV2MethodTransformer(), + new RedundantCheckCastEliminationMethodTransformer(), new RedundantBoxingMethodTransformer(), new RedundantCoercionToUnitTransformer(), new DeadCodeEliminationMethodTransformer(), diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt new file mode 100644 index 00000000000..bef06c321e7 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2017 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.optimization + +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter +import org.jetbrains.kotlin.codegen.optimization.fixStack.top +import org.jetbrains.kotlin.codegen.optimization.nullCheck.popReferenceValueBefore +import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.tree.* + +class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() { + override fun transform(internalClassName: String, methodNode: MethodNode) { + val insns = methodNode.instructions.toArray() + if (!insns.any { it.opcode == Opcodes.CHECKCAST }) return + + val redundantCheckCasts = ArrayList() + + val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter()) + for (i in insns.indices) { + val valueType = frames[i]?.top()?.type ?: continue + val insn = insns[i] + if (ReifiedTypeInliner.isOperationReifiedMarker(insn.previous)) continue + + if (insn is TypeInsnNode) { + val insnType = Type.getObjectType(insn.desc) + if (!isTrivialSubtype(insnType, valueType)) continue + + if (insn.opcode == Opcodes.CHECKCAST) { + redundantCheckCasts.add(insn) + } + } + } + + redundantCheckCasts.forEach { + methodNode.instructions.remove(it) + } + } + + private fun isTrivialSubtype(superType: Type, subType: Type) = + superType == subType +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/checkcastAndInstanceOf.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/checkcastAndInstanceOf.kt index caa17e94201..fa4337128e9 100644 --- a/compiler/testData/codegen/bytecodeText/boxingOptimization/checkcastAndInstanceOf.kt +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/checkcastAndInstanceOf.kt @@ -20,4 +20,4 @@ fun bar() { // 0 valueOf // 0 Value\s\(\) // 2 INSTANCEOF -// 2 CHECKCAST +// 1 CHECKCAST diff --git a/compiler/testData/codegen/bytecodeText/checkcast/kt14811.kt b/compiler/testData/codegen/bytecodeText/checkcast/kt14811.kt new file mode 100644 index 00000000000..59bb129d64b --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/checkcast/kt14811.kt @@ -0,0 +1,12 @@ +interface WorldObject { + val name: String +} + +fun testB(worldObj: WorldObject) { + val y = worldObj.let { + println("object name: ${it.name}") + it + } +} + +// 0 CHECKCAST \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/checkcast/kt14963.kt b/compiler/testData/codegen/bytecodeText/checkcast/kt14963.kt new file mode 100644 index 00000000000..4be5f177607 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/checkcast/kt14963.kt @@ -0,0 +1,3 @@ +fun f(o: Any): T = o as T + +// 0 CHECKCAST \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index eef5708288d..2a229373c54 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -713,6 +713,18 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/checkcast"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("kt14811.kt") + public void testKt14811() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/checkcast/kt14811.kt"); + doTest(fileName); + } + + @TestMetadata("kt14963.kt") + public void testKt14963() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/checkcast/kt14963.kt"); + doTest(fileName); + } + @TestMetadata("kt15411.kt") public void testKt15411() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/checkcast/kt15411.kt"); diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/simpleFragmentProperty/simpleFragmentProperty.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/simpleFragmentProperty/simpleFragmentProperty.kt index f15977f0baa..80181c0d5b7 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/simpleFragmentProperty/simpleFragmentProperty.kt +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/simpleFragmentProperty/simpleFragmentProperty.kt @@ -17,5 +17,4 @@ public class MyFragment : Fragment() { // 1 INVOKEVIRTUAL android/app/Activity\.getFragmentManager // 1 INVOKEVIRTUAL android/app/Fragment\.getFragmentManager // 2 GETSTATIC test/R\$id\.fragm -// 2 INVOKEVIRTUAL android/app/FragmentManager\.findFragmentById -// 2 CHECKCAST android/app/Fragment \ No newline at end of file +// 2 INVOKEVIRTUAL android/app/FragmentManager\.findFragmentById \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/supportSimpleFragmentProperty/supportSimpleFragmentProperty.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/supportSimpleFragmentProperty/supportSimpleFragmentProperty.kt index e82c6721629..93ca93345c6 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/supportSimpleFragmentProperty/supportSimpleFragmentProperty.kt +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/supportSimpleFragmentProperty/supportSimpleFragmentProperty.kt @@ -28,5 +28,4 @@ public class MyFragment : Fragment() { // 1 INVOKEVIRTUAL android/support/v4/app/FragmentActivity\.getSupportFragmentManager // 1 INVOKEVIRTUAL android/support/v4/app/Fragment\.getFragmentManager // 2 GETSTATIC test/R\$id\.fragm -// 2 INVOKEVIRTUAL android/support/v4/app/FragmentManager\.findFragmentById -// 2 CHECKCAST android/support/v4/app/Fragment \ No newline at end of file +// 2 INVOKEVIRTUAL android/support/v4/app/FragmentManager\.findFragmentById \ No newline at end of file