Eliminate redundant CHECKCAST instructions

CHECKCAST is redundant if the corresponding static type exactly matches the target type.
CHECKCAST instructions to-be-reified should not be eliminated.

KT-14811 Unnecessary checkcast generated in parameterized functions
KT-14963 unnecessary checkcast java/lang/Object
This commit is contained in:
Dmitry Petrov
2017-02-15 11:36:49 +03:00
parent ec403bfdbc
commit a087ea559f
8 changed files with 91 additions and 5 deletions
@@ -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(),
@@ -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<TypeInsnNode>()
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
}
@@ -20,4 +20,4 @@ fun bar() {
// 0 valueOf
// 0 Value\s\(\)
// 2 INSTANCEOF
// 2 CHECKCAST
// 1 CHECKCAST
@@ -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
@@ -0,0 +1,3 @@
fun <T> f(o: Any): T = o as T
// 0 CHECKCAST
@@ -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");
@@ -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
// 2 INVOKEVIRTUAL android/app/FragmentManager\.findFragmentById
@@ -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
// 2 INVOKEVIRTUAL android/support/v4/app/FragmentManager\.findFragmentById