Minor: reformat code in org.jetbrains.kotlin.codegen.optimization

This commit is contained in:
Dmitry Petrov
2018-01-24 14:13:36 +03:00
parent e12deb54d6
commit bd25bf14df
35 changed files with 645 additions and 652 deletions
@@ -17,13 +17,7 @@
package org.jetbrains.kotlin.codegen.optimization package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.codegen.optimization.common.ProperTrackedReferenceValue import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.common.ReferenceTrackingInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.ReferenceValueDescriptor
import org.jetbrains.kotlin.codegen.optimization.common.TrackedReferenceValue
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
@@ -195,8 +189,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
if (descriptor.localVar == null) { if (descriptor.localVar == null) {
descriptor.localVar = localVar descriptor.localVar = localVar
} } else {
else {
descriptor.hazard = true descriptor.hazard = true
} }
} }
@@ -210,8 +203,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
refValue.localVarIndex = methodNode.maxLocals refValue.localVarIndex = methodNode.maxLocals
methodNode.maxLocals += 2 methodNode.maxLocals += 2
localVar.index = refValue.localVarIndex localVar.index = refValue.localVarIndex
} } else {
else {
refValue.localVarIndex = localVar.index refValue.localVarIndex = localVar.index
} }
@@ -223,7 +215,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
} }
val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions) val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions)
if (cleanInstructions.size > 1 ) { if (cleanInstructions.size > 1) {
refValue.hazard = true refValue.hazard = true
continue continue
} }
@@ -239,7 +231,9 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
}.filter { }.filter {
val operationIndex = instructions.indexOf(it) val operationIndex = instructions.indexOf(it)
val localVariableNode = refValue.localVar!! val localVariableNode = refValue.localVar!!
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end) instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(
localVariableNode.end
)
}.toList() }.toList()
} }
@@ -55,9 +55,9 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
val frame = frames[i] ?: continue val frame = frames[i] ?: continue
val insn = insns[i] as? JumpInsnNode ?: continue val insn = insns[i] as? JumpInsnNode ?: continue
when (insn.opcode) { when (insn.opcode) {
in Opcodes.IFEQ .. Opcodes.IFLE -> in Opcodes.IFEQ..Opcodes.IFLE ->
tryRewriteComparisonWithZero(insn, frame, actions) tryRewriteComparisonWithZero(insn, frame, actions)
in Opcodes.IF_ICMPEQ .. Opcodes.IF_ICMPLE -> in Opcodes.IF_ICMPEQ..Opcodes.IF_ICMPLE ->
tryRewriteBinaryComparison(insn, frame, actions) tryRewriteBinaryComparison(insn, frame, actions)
} }
} }
@@ -93,8 +93,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
if (arg1 is IConstValue && arg2 is IConstValue) { if (arg1 is IConstValue && arg2 is IConstValue) {
rewriteBinaryComparisonOfConsts(insn, arg1.value, arg2.value, actions) rewriteBinaryComparisonOfConsts(insn, arg1.value, arg2.value, actions)
} } else if (arg2 is IConstValue && arg2.value == 0) {
else if (arg2 is IConstValue && arg2.value == 0) {
rewriteBinaryComparisonWith0(insn, actions) rewriteBinaryComparisonWith0(insn, actions)
} }
} }
@@ -155,7 +154,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
private val ICONST_CACHE = Array(7) { IConstValue(it - 1) } private val ICONST_CACHE = Array(7) { IConstValue(it - 1) }
fun of(value: Int) = fun of(value: Int) =
if (value in -1 .. 5) if (value in -1..5)
ICONST_CACHE[value + 1] ICONST_CACHE[value + 1]
else else
IConstValue(value) IConstValue(value)
@@ -165,7 +164,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() {
private class ConstantPropagationInterpreter : OptimizationBasicInterpreter() { private class ConstantPropagationInterpreter : OptimizationBasicInterpreter() {
override fun newOperation(insn: AbstractInsnNode): BasicValue = override fun newOperation(insn: AbstractInsnNode): BasicValue =
when (insn.opcode) { when (insn.opcode) {
in Opcodes.ICONST_M1 .. Opcodes.ICONST_5 -> in Opcodes.ICONST_M1..Opcodes.ICONST_5 ->
IConstValue.of(insn.opcode - Opcodes.ICONST_0) IConstValue.of(insn.opcode - Opcodes.ICONST_0)
Opcodes.BIPUSH, Opcodes.SIPUSH -> Opcodes.BIPUSH, Opcodes.SIPUSH ->
IConstValue.of(insn.cast<IntInsnNode>().operand) IConstValue.of(insn.cast<IntInsnNode>().operand)
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class FixStackWithLabelNormalizationMethodTransformer : CompositeMethodTransformer( class FixStackWithLabelNormalizationMethodTransformer : CompositeMethodTransformer(
LabelNormalizationMethodTransformer(), LabelNormalizationMethodTransformer(),
@@ -49,13 +49,11 @@ class LabelNormalizationMethodTransformer : MethodTransformer() {
newLabelNodes[thisNode.label] = prevNode newLabelNodes[thisNode.label] = prevNode
removedAnyLabels = true removedAnyLabels = true
thisNode = instructions.removeNodeGetNext(thisNode) thisNode = instructions.removeNodeGetNext(thisNode)
} } else {
else {
newLabelNodes[thisNode.label] = thisNode newLabelNodes[thisNode.label] = thisNode
thisNode = thisNode.next thisNode = thisNode.next
} }
} } else {
else {
thisNode = thisNode.next thisNode = thisNode.next
} }
} }
@@ -24,8 +24,7 @@ class MethodVerifier(private val checkPoint: String) : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) { override fun transform(internalClassName: String, methodNode: MethodNode) {
try { try {
analyze(internalClassName, methodNode, BasicVerifier()) analyze(internalClassName, methodNode, BasicVerifier())
} } catch (e: Throwable) {
catch (e: Throwable) {
throw AssertionError("$checkPoint: incorrect bytecode", e) throw AssertionError("$checkPoint: incorrect bytecode", e)
} }
} }
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() { class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) { override fun transform(internalClassName: String, methodNode: MethodNode) {
@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.codegen.optimization package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class RedundantGotoMethodTransformer : MethodTransformer() { class RedundantGotoMethodTransformer : MethodTransformer() {
/** /**
@@ -46,8 +46,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
val toRemove = current val toRemove = current
current = current.next current = current.next
methodNode.instructions.remove(toRemove) methodNode.instructions.remove(toRemove)
} } else {
else {
current = current.next current = current.next
} }
} }
@@ -84,7 +83,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
} }
for (i in 0 .. localVariableLabels.size - 2) { for (i in 0..localVariableLabels.size - 2) {
val begin = localVariableLabels[i] val begin = localVariableLabels[i]
val end = localVariableLabels[i + 1] val end = localVariableLabels[i + 1]
if (InsnSequence(begin, end).any { it in requiredNops }) continue if (InsnSequence(begin, end).any { it in requiredNops }) continue
@@ -109,8 +108,7 @@ internal fun getRequiredNopInRange(firstInclusive: AbstractInsnNode, lastExclusi
while (current != null && current != lastExclusive) { while (current != null && current != lastExclusive) {
if (current.isMeaningful && current.opcode != Opcodes.NOP) { if (current.isMeaningful && current.opcode != Opcodes.NOP) {
return null return null
} } else if (current.opcode == Opcodes.NOP) {
else if (current.opcode == Opcodes.NOP) {
lastNop = current lastNop = current
} }
current = current.next current = current.next
@@ -36,7 +36,11 @@ import java.util.*
open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() { open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() {
private val boxingPlaces = HashMap<Int, BoxedBasicValue>() private val boxingPlaces = HashMap<Int, BoxedBasicValue>()
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue = protected open fun createNewBoxing(
insn: AbstractInsnNode,
type: Type,
progressionIterator: ProgressionIteratorBasicValue?
): BasicValue =
boxingPlaces.getOrPut(insnList.indexOf(insn)) { boxingPlaces.getOrPut(insnList.indexOf(insn)) {
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator) val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
onNewBoxedValue(boxedBasicValue) onNewBoxedValue(boxedBasicValue)
@@ -145,7 +145,12 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
return super.binaryOperation(insn, value1, value2) return super.binaryOperation(insn, value1, value2)
} }
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue { override fun ternaryOperation(
insn: AbstractInsnNode,
value1: SourceValue,
value2: SourceValue,
value3: SourceValue
): SourceValue {
value1.insns.markAsDontTouch() value1.insns.markAsDontTouch()
value2.insns.markAsDontTouch() value2.insns.markAsDontTouch()
value3.insns.markAsDontTouch() value3.insns.markAsDontTouch()
@@ -193,8 +198,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) { if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) {
transformations[insn] = replaceWithNopTransformation() transformations[insn] = replaceWithNopTransformation()
sources.forEach { propagatePopBackwards(it, inputTop.size) } sources.forEach { propagatePopBackwards(it, inputTop.size) }
} } else {
else {
transformations[insn] = insertPopAfterTransformation(poppedValueSize) transformations[insn] = insertPopAfterTransformation(poppedValueSize)
} }
} }
@@ -214,8 +218,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
if (sources.all { !isDontTouch(it) }) { if (sources.all { !isDontTouch(it) }) {
transformations[insn] = replaceWithNopTransformation() transformations[insn] = replaceWithNopTransformation()
sources.forEach { propagatePopBackwards(it, inputTop.size) } sources.forEach { propagatePopBackwards(it, inputTop.size) }
} } else {
else {
transformations[insn] = replaceWithPopTransformation(poppedValueSize) transformations[insn] = replaceWithPopTransformation(poppedValueSize)
} }
} }
@@ -252,8 +255,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
while (node != null && node != end) { while (node != null && node != end) {
if (node in removableNops && !keepNop) { if (node in removableNops && !keepNop) {
node = insnList.removeNodeGetNext(node) node = insnList.removeNodeGetNext(node)
} } else {
else {
if (node.isMeaningful) keepNop = false if (node.isMeaningful) keepNop = false
node = node.next node = node.next
} }
@@ -300,7 +302,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
fun AbstractInsnNode.isPurePush() = fun AbstractInsnNode.isPurePush() =
isLoadOperation() || isLoadOperation() ||
opcode in Opcodes.ACONST_NULL .. Opcodes.LDC + 2 || opcode in Opcodes.ACONST_NULL..Opcodes.LDC + 2 ||
isUnitInstance() isUnitInstance()
fun AbstractInsnNode.isPop() = fun AbstractInsnNode.isPop() =
@@ -311,4 +313,4 @@ fun AbstractInsnNode.isUnitInstance() =
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE" this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
fun AbstractInsnNode.isPrimitiveTypeConversion() = fun AbstractInsnNode.isPrimitiveTypeConversion() =
opcode in Opcodes.I2L .. Opcodes.I2S opcode in Opcodes.I2L..Opcodes.I2S
@@ -30,6 +30,7 @@ import org.jetbrains.org.objectweb.asm.Type;
public class ProgressionIteratorBasicValue extends StrictBasicValue { public class ProgressionIteratorBasicValue extends StrictBasicValue {
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE; private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
static { static {
ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder(); ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder();
for (PrimitiveType primitiveType : RangeCodegenUtilKt.getSupportedRangeTypes()) { for (PrimitiveType primitiveType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
@@ -39,6 +40,7 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
} }
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE; private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
static { static {
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder(); ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) { for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
@@ -116,8 +116,7 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) { if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) {
markValueAsDirty(value) markValueAsDirty(value)
} } else {
else {
addAssociatedInsn(value, insnNode) addAssociatedInsn(value, insnNode)
} }
} }
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
import org.jetbrains.kotlin.codegen.inline.insnText import org.jetbrains.kotlin.codegen.inline.insnText
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.optimization.common.* import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
@@ -32,7 +32,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import java.util.* import java.util.*
class RedundantBoxingMethodTransformer : MethodTransformer() { class RedundantBoxingMethodTransformer : MethodTransformer() {
@@ -171,8 +170,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
(insn as VarInsnNode).`var` == localVariableNode.index) { (insn as VarInsnNode).`var` == localVariableNode.index) {
if (insn.getOpcode() == Opcodes.ASTORE) { if (insn.getOpcode() == Opcodes.ASTORE) {
values.add(frame.top()!!) values.add(frame.top()!!)
} } else {
else {
values.add(frame.getLocal(insn.`var`)) values.add(frame.getLocal(insn.`var`))
} }
} }
@@ -228,8 +226,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
private fun adaptBoxingInstruction(node: MethodNode, value: BoxedValueDescriptor) { private fun adaptBoxingInstruction(node: MethodNode, value: BoxedValueDescriptor) {
if (!value.isFromProgressionIterator()) { if (!value.isFromProgressionIterator()) {
node.instructions.remove(value.boxingInsn) node.instructions.remove(value.boxingInsn)
} } else {
else {
val iterator = value.progressionIterator ?: error("iterator should not be null because isFromProgressionIterator returns true") val iterator = value.progressionIterator ?: error("iterator should not be null because isFromProgressionIterator returns true")
//add checkcast to kotlin/<T>Iterator before next() call //add checkcast to kotlin/<T>Iterator before next() call
@@ -309,8 +306,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
Opcodes.INVOKEINTERFACE -> { Opcodes.INVOKEINTERFACE -> {
if (insn.isJavaLangComparableCompareTo()) { if (insn.isJavaLangComparableCompareTo()) {
adaptJavaLangComparableCompareTo(node, insn, value) adaptJavaLangComparableCompareTo(node, insn, value)
} } else {
else {
throwCannotAdaptInstruction(insn) throwCannotAdaptInstruction(insn)
} }
} }
@@ -339,8 +335,8 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
adaptAreEqualIntrinsicForInt(node, insn) adaptAreEqualIntrinsicForInt(node, insn)
Type.LONG -> Type.LONG ->
adaptAreEqualIntrinsicForLong(node, insn) adaptAreEqualIntrinsicForLong(node, insn)
Type.OBJECT -> Type.OBJECT -> {
{} }
else -> else ->
throw AssertionError("Unexpected unboxed type kind: $unboxedType") throw AssertionError("Unexpected unboxed type kind: $unboxedType")
} }
@@ -353,8 +349,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
fuseAreEqualWithBranch(node, insn, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPEQ) fuseAreEqualWithBranch(node, insn, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPEQ)
remove(insn) remove(insn)
remove(next) remove(next)
} } else {
else {
ifEqual1Else0(node, insn, Opcodes.IF_ICMPNE) ifEqual1Else0(node, insn, Opcodes.IF_ICMPNE)
remove(insn) remove(insn)
} }
@@ -369,8 +364,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
fuseAreEqualWithBranch(node, insn, Opcodes.IFNE, Opcodes.IFEQ) fuseAreEqualWithBranch(node, insn, Opcodes.IFNE, Opcodes.IFEQ)
remove(insn) remove(insn)
remove(next) remove(next)
} } else {
else {
ifEqual1Else0(node, insn, Opcodes.IFNE) ifEqual1Else0(node, insn, Opcodes.IFNE)
remove(insn) remove(insn)
} }
@@ -84,8 +84,7 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() {
it.set(insn, InsnNode(Opcodes.NOP)) it.set(insn, InsnNode(Opcodes.NOP))
it.remove(prevNonNop) it.remove(prevNonNop)
} }
} } else if (i > 1) {
else if (i > 1) {
val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) { if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) {
actions.add { actions.add {
@@ -116,8 +116,7 @@ open class MethodAnalyzer<V : Value>(
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(f, insn) visitNopInsn(f, insn)
} } else {
else {
current.init(f).execute(insnNode, interpreter) current.init(f).execute(insnNode, interpreter)
when { when {
@@ -129,12 +128,13 @@ open class MethodAnalyzer<V : Value>(
visitTableSwitchInsnNode(insnNode, current, insn) visitTableSwitchInsnNode(insnNode, current, insn)
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) -> insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
visitOpInsn(current, insn) visitOpInsn(current, insn)
else -> {} else -> {
}
} }
} }
handlers[insn]?.forEach { tcb -> handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type?:"java/lang/Throwable") val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = instructions.indexOf(tcb.handler) val jump = instructions.indexOf(tcb.handler)
if (visitControlFlowExceptionEdge(insn, tcb)) { if (visitControlFlowExceptionEdge(insn, tcb)) {
handler.init(f) handler.init(f)
@@ -144,11 +144,9 @@ open class MethodAnalyzer<V : Value>(
} }
} }
} } catch (e: AnalyzerException) {
catch (e: AnalyzerException) {
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e) throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
} } catch (e: Exception) {
catch (e: Exception) {
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e) throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
} }
@@ -40,7 +40,7 @@ abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
super.merge(v, w) super.merge(v, w)
} }
protected fun createTaintedValue(v: BasicValue, w: BasicValue) : TrackedReferenceValue = protected fun createTaintedValue(v: BasicValue, w: BasicValue): TrackedReferenceValue =
TaintedTrackedReferenceValue( TaintedTrackedReferenceValue(
getMergedValueType(v.type, w.type), getMergedValueType(v.type, w.type),
mergeDescriptors(v, w).also { mergeDescriptors(v, w).also {
@@ -74,8 +74,7 @@ abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
if (value is TrackedReferenceValue) { if (value is TrackedReferenceValue) {
checkRefValuesUsages(insn, listOf(value)) checkRefValuesUsages(insn, listOf(value))
value value
} } else {
else {
super.copyOperation(insn, value) super.copyOperation(insn, value)
} }
@@ -22,7 +22,7 @@ interface ReferenceValueDescriptor {
fun onUseAsTainted() fun onUseAsTainted()
} }
sealed class TrackedReferenceValue(type: Type): StrictBasicValue(type) { sealed class TrackedReferenceValue(type: Type) : StrictBasicValue(type) {
abstract val descriptors: Set<ReferenceValueDescriptor> abstract val descriptors: Set<ReferenceValueDescriptor>
} }
@@ -62,6 +62,7 @@ class TaintedTrackedReferenceValue(type: Type, override val descriptors: Set<Ref
override fun hashCode(): Int = override fun hashCode(): Int =
descriptors.hashCode() descriptors.hashCode()
override fun toString(): String = override fun toString(): String =
"!$descriptors" "!$descriptors"
} }
@@ -27,7 +27,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.*
val AbstractInsnNode.isMeaningful: Boolean get() = val AbstractInsnNode.isMeaningful: Boolean
get() =
when (this.type) { when (this.type) {
AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false
else -> true else -> true
@@ -44,6 +45,7 @@ class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequ
current = current!!.next current = current!!.next
return result!! return result!!
} }
override fun hasNext() = current != to override fun hasNext() = current != to
} }
} }
@@ -74,13 +76,15 @@ fun MethodNode.prepareForEmitting() {
current = prev current = prev
} }
maxStack = -1 maxStack = -1
accept(MaxStackFrameSizeAndLocalsCalculator( accept(
MaxStackFrameSizeAndLocalsCalculator(
Opcodes.ASM5, access, desc, Opcodes.ASM5, access, desc,
object : MethodVisitor(Opcodes.ASM5) { object : MethodVisitor(Opcodes.ASM5) {
override fun visitMaxs(maxStack: Int, maxLocals: Int) { override fun visitMaxs(maxStack: Int, maxLocals: Int) {
this@prepareForEmitting.maxStack = maxStack this@prepareForEmitting.maxStack = maxStack
} }
})) })
)
} }
fun MethodNode.stripOptimizationMarkers() { fun MethodNode.stripOptimizationMarkers() {
@@ -88,8 +92,7 @@ fun MethodNode.stripOptimizationMarkers() {
while (insn != null) { while (insn != null) {
if (isOptimizationMarker(insn)) { if (isOptimizationMarker(insn)) {
insn = instructions.removeNodeGetNext(insn) insn = instructions.removeNodeGetNext(insn)
} } else {
else {
insn = insn.next insn = insn.next
} }
} }
@@ -192,7 +195,8 @@ fun AbstractInsnNode.hasOpcode(): Boolean =
// mv.visitLdcInsn(new Integer(cst)); // mv.visitLdcInsn(new Integer(cst));
// } // }
// } // }
val AbstractInsnNode.intConstant: Int? get() = val AbstractInsnNode.intConstant: Int?
get() =
when (opcode) { when (opcode) {
in ICONST_M1..ICONST_5 -> opcode - ICONST_0 in ICONST_M1..ICONST_5 -> opcode - ICONST_0
BIPUSH, SIPUSH -> (this as IntInsnNode).operand BIPUSH, SIPUSH -> (this as IntInsnNode).operand
@@ -205,7 +209,8 @@ fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEac
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
val AbstractInsnNode?.debugText get() = val AbstractInsnNode?.debugText
get() =
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText" if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean = internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean =
@@ -51,6 +51,7 @@ class VariableLivenessFrame(val maxLocals: Int) : VarFrame<VariableLivenessFrame
override fun hashCode() = bitSet.hashCode() override fun hashCode() = bitSet.hashCode()
} }
fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> { fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter()) val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> { return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> {
@@ -85,8 +86,7 @@ private fun useVar(
if (insn is VarInsnNode && insn.isLoadOperation()) { if (insn is VarInsnNode && insn.isLoadOperation()) {
frame.markAlive(insn.`var`) frame.markAlive(insn.`var`)
} } else if (insn is IincInsnNode) {
else if (insn is IincInsnNode) {
frame.markAlive(insn.`var`) frame.markAlive(insn.`var`)
} }
} }
@@ -30,7 +30,7 @@ import java.util.*
private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) { private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) {
// Only used for assertions // Only used for assertions
var defaultHandlerTcb : TryCatchBlockNode? = null var defaultHandlerTcb: TryCatchBlockNode? = null
val handlerStartLabels = hashSetOf<LabelNode>() val handlerStartLabels = hashSetOf<LabelNode>()
} }
@@ -92,8 +92,7 @@ private fun insertSaveRestoreStackMarkers(
methodNode.instructions.insertBefore(nopNode, saveStackMarker) methodNode.instructions.insertBefore(nopNode, saveStackMarker)
methodNode.instructions.insertBefore(nopNode, newTryStartLabel) methodNode.instructions.insertBefore(nopNode, newTryStartLabel)
methodNode.instructions.insert(nopNode, restoreStackMarker) methodNode.instructions.insert(nopNode, restoreStackMarker)
} } else {
else {
saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!! saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!!
} }
@@ -24,7 +24,10 @@ import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
@@ -128,8 +131,7 @@ internal class FixStackAnalyzer(
override fun push(value: BasicValue) { override fun push(value: BasicValue) {
if (super.getStackSize() < maxStackSize) { if (super.getStackSize() < maxStackSize) {
super.push(value) super.push(value)
} } else {
else {
extraStack.add(value) extraStack.add(value)
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size) maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
} }
@@ -142,8 +144,7 @@ internal class FixStackAnalyzer(
override fun pop(): BasicValue { override fun pop(): BasicValue {
return if (extraStack.isNotEmpty()) { return if (extraStack.isNotEmpty()) {
extraStack.pop() extraStack.pop()
} } else {
else {
super.pop() super.pop()
} }
} }
@@ -151,8 +152,7 @@ internal class FixStackAnalyzer(
override fun getStack(i: Int): BasicValue { override fun getStack(i: Int): BasicValue {
return if (i < super.getMaxStackSize()) { return if (i < super.getMaxStackSize()) {
super.getStack(i) super.getStack(i)
} } else {
else {
extraStack[i - maxStackSize] extraStack[i - maxStackSize]
} }
} }
@@ -176,8 +176,7 @@ internal class FixStackAnalyzer(
val savedValues = spilledStacks[beforeInlineMarker] val savedValues = spilledStacks[beforeInlineMarker]
pushAll(savedValues!!) pushAll(savedValues!!)
push(returnValue) push(returnValue)
} } else {
else {
val savedValues = spilledStacks[beforeInlineMarker] val savedValues = spilledStacks[beforeInlineMarker]
pushAll(savedValues!!) pushAll(savedValues!!)
} }
@@ -197,5 +196,4 @@ internal class FixStackAnalyzer(
} }
} }
@@ -108,11 +108,9 @@ class FixStackMethodTransformer : MethodTransformer() {
val actualStackContent = analyzer.getActualStack(gotoNode) val actualStackContent = analyzer.getActualStack(gotoNode)
?: throw AssertionError("Jump at $gotoIndex should be alive") ?: throw AssertionError("Jump at $gotoIndex should be alive")
actions.add { replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) } actions.add { replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) }
} } else if (actualStackSize >= 0 && expectedStackSize < 0) {
else if (actualStackSize >= 0 && expectedStackSize < 0) {
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex") throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
} } else {
else {
val marker = gotoNode.previous val marker = gotoNode.previous
actions.add { methodNode.instructions.remove(marker) } actions.add { methodNode.instructions.remove(marker) }
} }
@@ -152,8 +150,7 @@ class FixStackMethodTransformer : MethodTransformer() {
if (savedStackValues != null) { if (savedStackValues != null) {
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues) val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
actions.add { saveStack(methodNode, marker, savedStackDescriptor) } actions.add { saveStack(methodNode, marker, savedStackDescriptor) }
} } else {
else {
// marker is dead code // marker is dead code
localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList()) localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList())
actions.add { methodNode.instructions.remove(marker) } actions.add { methodNode.instructions.remove(marker) }
@@ -186,7 +183,8 @@ class FixStackMethodTransformer : MethodTransformer() {
val returnValue = stackContentAfterInline.last() val returnValue = stackContentAfterInline.last()
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue) val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
actions.add { actions.add {
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor, restoreStackWithReturnValue(
methodNode, inlineMarker, savedStackDescriptor,
returnValue, returnValueLocalVarIndex returnValue, returnValueLocalVarIndex
) )
} }
@@ -196,8 +194,7 @@ class FixStackMethodTransformer : MethodTransformer() {
else -> else ->
throw AssertionError("Inline method should not leave more than 1 value on stack") throw AssertionError("Inline method should not leave more than 1 value on stack")
} }
} } else {
else {
// after inline marker is dead code // after inline marker is dead code
actions.add { methodNode.instructions.remove(inlineMarker) } actions.add { methodNode.instructions.remove(inlineMarker) }
} }
@@ -215,8 +212,7 @@ class FixStackMethodTransformer : MethodTransformer() {
if (savedStackValues != null) { if (savedStackValues != null) {
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues) val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
actions.add { saveStack(methodNode, inlineMarker, savedStackDescriptor) } actions.add { saveStack(methodNode, inlineMarker, savedStackDescriptor) }
} } else {
else {
// before inline marker is dead code // before inline marker is dead code
localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList()) localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList())
actions.add { methodNode.instructions.remove(inlineMarker) } actions.add { methodNode.instructions.remove(inlineMarker) }
@@ -43,7 +43,11 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues) return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
} }
private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor { private fun allocateNewHandle(
numRestoreStackMarkers: Int,
saveStackMarker: AbstractInsnNode,
savedStackValues: List<BasicValue>
): SavedStackDescriptor {
if (savedStackValues.any { it.type == null }) { if (savedStackValues.any { it.type == null }) {
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}") throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
} }
@@ -62,8 +66,8 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
} }
private fun getFirstUnusedLocalVariableIndex(): Int = private fun getFirstUnusedLocalVariableIndex(): Int =
allocatedHandles.values.fold(initialMaxLocals) { allocatedHandles.values.fold(initialMaxLocals) { index, handle ->
index, handle -> Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex) Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex)
} }
fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) { fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) {
@@ -71,7 +75,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
markEmitted(saveStackMarker!!) markEmitted(saveStackMarker!!)
} }
fun allocateVariablesForBeforeInlineMarker(beforeInlineMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor { fun allocateVariablesForBeforeInlineMarker(
beforeInlineMarker: AbstractInsnNode,
savedStackValues: List<BasicValue>
): SavedStackDescriptor {
return allocateNewHandle(1, beforeInlineMarker, savedStackValues) return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
} }
@@ -102,8 +102,10 @@ fun restoreStackWithReturnValue(
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) { fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
var localVarIndex = savedStackDescriptor.firstLocalVarIndex var localVarIndex = savedStackDescriptor.firstLocalVarIndex
for (value in savedStackDescriptor.savedValues) { for (value in savedStackDescriptor.savedValues) {
methodNode.instructions.insertBefore(location, methodNode.instructions.insertBefore(
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)) location,
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)
)
localVarIndex += value.size localVarIndex += value.size
} }
} }
@@ -112,27 +114,31 @@ fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
for (value in savedStackDescriptor.savedValues.asReversed()) { for (value in savedStackDescriptor.savedValues.asReversed()) {
localVarIndex -= value.size localVarIndex -= value.size
methodNode.instructions.insertBefore(location, methodNode.instructions.insertBefore(
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)) location,
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)
)
} }
} }
fun getPopInstruction(top: BasicValue) = fun getPopInstruction(top: BasicValue) =
InsnNode(when (top.size) { InsnNode(
when (top.size) {
1 -> Opcodes.POP 1 -> Opcodes.POP
2 -> Opcodes.POP2 2 -> Opcodes.POP2
else -> throw AssertionError("Unexpected value type size") else -> throw AssertionError("Unexpected value type size")
}) }
)
fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) { fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) {
with (methodNode.instructions) { with(methodNode.instructions) {
remove(node.next) remove(node.next)
remove(node) remove(node)
} }
} }
fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) { fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) {
with (methodNode.instructions) { with(methodNode.instructions) {
val next = node.next as JumpInsnNode val next = node.next as JumpInsnNode
insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label)) insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label))
remove(node) remove(node)
@@ -141,7 +147,7 @@ fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode
} }
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<BasicValue>) { fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<BasicValue>) {
with (methodNode.instructions) { with(methodNode.instructions) {
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) { for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
insert(node, getPopInstruction(stackValue)) insert(node, getPopInstruction(stackValue))
} }
@@ -37,7 +37,8 @@ import org.jetbrains.org.objectweb.asm.tree.*
class RedundantNullCheckMethodTransformer : MethodTransformer() { class RedundantNullCheckMethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) { override fun transform(internalClassName: String, methodNode: MethodNode) {
while (TransformerPass(internalClassName, methodNode).run()) {} while (TransformerPass(internalClassName, methodNode).run()) {
}
} }
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) { private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) {
@@ -108,8 +109,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
popReferenceValueBefore(insn) popReferenceValueBefore(insn)
if (alwaysTrue) { if (alwaysTrue) {
set(insn, JumpInsnNode(Opcodes.GOTO, insn.label)) set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
} } else {
else {
remove(insn) remove(insn)
} }
} }
@@ -120,8 +120,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
if (nullability == Nullability.NULL) { if (nullability == Nullability.NULL) {
changes = true changes = true
transformTrivialInstanceOf(insn, false) transformTrivialInstanceOf(insn, false)
} } else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) {
else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) {
changes = true changes = true
transformTrivialInstanceOf(insn, true) transformTrivialInstanceOf(insn, true)
} }
@@ -160,8 +159,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
val previous = insn.previous ?: continue@insnLoop val previous = insn.previous ?: continue@insnLoop
if (previous.opcode == Opcodes.ALOAD) { if (previous.opcode == Opcodes.ALOAD) {
addDependentCheck(insn, previous as VarInsnNode) addDependentCheck(insn, previous as VarInsnNode)
} } else if (previous.opcode == Opcodes.DUP) {
else if (previous.opcode == Opcodes.DUP) {
val previous2 = previous.previous ?: continue@insnLoop val previous2 = previous.previous ?: continue@insnLoop
if (previous2.opcode == Opcodes.ALOAD) { if (previous2.opcode == Opcodes.ALOAD) {
addDependentCheck(insn, previous2 as VarInsnNode) addDependentCheck(insn, previous2 as VarInsnNode)
@@ -184,8 +182,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
val insn1 = ldcInsn.previous ?: continue@insnLoop val insn1 = ldcInsn.previous ?: continue@insnLoop
if (insn1.opcode == Opcodes.ALOAD) { if (insn1.opcode == Opcodes.ALOAD) {
aLoadInsn = insn1 as VarInsnNode aLoadInsn = insn1 as VarInsnNode
} } else if (insn1.opcode == Opcodes.DUP) {
else if (insn1.opcode == Opcodes.DUP) {
val insn2 = insn1.previous ?: continue@insnLoop val insn2 = insn1.previous ?: continue@insnLoop
if (insn2.opcode == Opcodes.ALOAD) { if (insn2.opcode == Opcodes.ALOAD) {
aLoadInsn = insn2 as VarInsnNode aLoadInsn = insn2 as VarInsnNode
@@ -318,8 +315,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
methodNode.instructions.add(newLabel) methodNode.instructions.add(newLabel)
next.label = newLabel next.label = newLabel
insertAfterNotNull = newLabel insertAfterNotNull = newLabel
} } else {
else {
originalLabel = null originalLabel = null
insertAfterNotNull = next insertAfterNotNull = next
} }
@@ -37,6 +37,7 @@ object NullBasicValue : StrictBasicValue(AsmTypes.OBJECT_TYPE)
enum class Nullability { enum class Nullability {
NULL, NOT_NULL, NULLABLE; NULL, NOT_NULL, NULLABLE;
fun isNull() = this == NULL fun isNull() = this == NULL
fun isNotNull() = this == NOT_NULL fun isNotNull() = this == NOT_NULL
} }