Refined redundant null check optimization
This commit is contained in:
+2
-2
@@ -55,7 +55,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private BoxedBasicValue createNewBoxing(
|
||||
protected BasicValue createNewBoxing(
|
||||
@NotNull AbstractInsnNode insn, @NotNull Type type,
|
||||
@Nullable ProgressionIteratorBasicValue progressionIterator
|
||||
) {
|
||||
@@ -201,7 +201,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return super.unaryOperation(insn, value);
|
||||
}
|
||||
|
||||
private static boolean isExactValue(@NotNull BasicValue value) {
|
||||
protected boolean isExactValue(@NotNull BasicValue value) {
|
||||
return value instanceof ProgressionIteratorBasicValue ||
|
||||
value instanceof BoxedBasicValue ||
|
||||
(value.getType() != null && isProgressionClass(value.getType().getInternalName()));
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.boxing
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.BasicValueWrapper
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
public class NullabilityInterpreter(insns: InsnList) : BoxingInterpreter(insns) {
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue) = makeNotNullIfNeeded(insn, super.unaryOperation(insn, value))
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode) = makeNotNullIfNeeded(insn, super.newOperation(insn))
|
||||
|
||||
override fun isExactValue(value: BasicValue) = super.isExactValue(value) || value is NotNullBasicValue
|
||||
|
||||
override fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?) =
|
||||
NotNullBasicValue(BasicValue(type))
|
||||
}
|
||||
|
||||
private fun makeNotNullIfNeeded(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
|
||||
when (insn.getOpcode()) {
|
||||
Opcodes.ANEWARRAY, Opcodes.NEWARRAY, Opcodes.LDC, Opcodes.NEW -> NotNullBasicValue(value)
|
||||
else -> value
|
||||
}
|
||||
|
||||
class NotNullBasicValue(wrappedValue: BasicValue?) : BasicValueWrapper(wrappedValue) {
|
||||
override fun equals(other: Any?): Boolean = other is NotNullBasicValue
|
||||
}
|
||||
+2
-3
@@ -39,7 +39,7 @@ public class RedundantNullCheckMethodTransformer extends MethodTransformer {
|
||||
InsnList insnList = methodNode.instructions;
|
||||
Frame<BasicValue>[] frames = analyze(
|
||||
internalClassName, methodNode,
|
||||
new BoxingInterpreter(insnList)
|
||||
new NullabilityInterpreter(insnList)
|
||||
);
|
||||
|
||||
List<AbstractInsnNode> insnsToOptimize = new ArrayList<AbstractInsnNode>();
|
||||
@@ -49,8 +49,7 @@ public class RedundantNullCheckMethodTransformer extends MethodTransformer {
|
||||
AbstractInsnNode insn = insnList.get(i);
|
||||
|
||||
if ((insn.getOpcode() == Opcodes.IFNULL || insn.getOpcode() == Opcodes.IFNONNULL) &&
|
||||
frame != null && frame.getStack(frame.getStackSize() - 1) instanceof BoxedBasicValue) {
|
||||
|
||||
frame != null && frame.getStack(frame.getStackSize() - 1) instanceof NotNullBasicValue) {
|
||||
insnsToOptimize.add(insn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,3 +69,11 @@ fun MethodNode.prepareForEmitting() {
|
||||
current = prev
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BasicValueWrapper(val wrappedValue: BasicValue?) : BasicValue(wrappedValue?.getType()) {
|
||||
val basicValue: BasicValue? get() = (wrappedValue as? BasicValueWrapper)?.basicValue ?: wrappedValue
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return super.equals(other) && this.javaClass == other?.javaClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fun box() {
|
||||
val x = Array(1) { "" }
|
||||
}
|
||||
|
||||
// 0 IFNULL
|
||||
// 0 IFNONNULL
|
||||
// 0 ATHROW
|
||||
// 0 throwNpe
|
||||
@@ -1,3 +1,5 @@
|
||||
class A
|
||||
|
||||
fun foo(x: Any?) {}
|
||||
|
||||
fun box() {
|
||||
@@ -8,6 +10,9 @@ fun box() {
|
||||
z!!
|
||||
|
||||
foo(1 as java.lang.Integer)
|
||||
|
||||
val y: Any? = if (1 == 1) x else A()
|
||||
y!!
|
||||
}
|
||||
|
||||
// 0 IFNULL
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fun box() {
|
||||
val x: Any? = "abc"
|
||||
val y: Any? = if (1 == 1) x else "cde"
|
||||
|
||||
x!!
|
||||
y!!
|
||||
}
|
||||
|
||||
// 0 IFNULL
|
||||
// 0 IFNONNULL
|
||||
// 0 throwNpe
|
||||
// 0 ATHROW
|
||||
@@ -0,0 +1,15 @@
|
||||
class A
|
||||
fun box() {
|
||||
val x: A? = A()
|
||||
val z: A? = A()
|
||||
val z1: A? = if (1 == 1) z else x
|
||||
|
||||
x!!
|
||||
z!!
|
||||
z1!!
|
||||
}
|
||||
|
||||
// 0 IFNULL
|
||||
// 0 IFNONNULL
|
||||
// 0 throwNpe
|
||||
// 0 ATHROW
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
class A
|
||||
fun box() {
|
||||
val x: A? = A()
|
||||
val y: A?
|
||||
if (1 == 0) {
|
||||
y = x
|
||||
}
|
||||
else {
|
||||
y = null
|
||||
}
|
||||
|
||||
y!!
|
||||
}
|
||||
|
||||
// 0 IFNULL
|
||||
// 1 IFNONNULL
|
||||
// 1 throwNpe
|
||||
// 0 ATHROW
|
||||
@@ -309,6 +309,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/deadCodeElimination"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("arrayConstructor.kt")
|
||||
public void testArrayConstructor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/arrayConstructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("boxing.kt")
|
||||
public void testBoxing() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt");
|
||||
@@ -326,6 +332,24 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/lastReturn.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("literal.kt")
|
||||
public void testLiteral() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/literal.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleConstructor.kt")
|
||||
public void testSimpleConstructor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructor.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleConstructorNotRedundant.kt")
|
||||
public void testSimpleConstructorNotRedundant() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/bytecodeText/directInvoke")
|
||||
|
||||
Reference in New Issue
Block a user