From 2ecb8896cc893ff5afb003f09347e136818d0d4d Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 3 Mar 2016 11:11:35 +0300 Subject: [PATCH] Converting optimization.boxing to Kotlin: convert & simplify --- .../optimization/boxing/BoxedBasicValue.kt | 157 +++------ .../optimization/boxing/BoxingInterpreter.kt | 333 +++++++----------- .../boxing/RedundantBoxingInterpreter.kt | 194 +++++----- 3 files changed, 260 insertions(+), 424 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt index 0623896d3aa..aaad810b444 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt @@ -14,121 +14,74 @@ * limitations under the License. */ -package org.jetbrains.kotlin.codegen.optimization.boxing; +package org.jetbrains.kotlin.codegen.optimization.boxing -import com.intellij.openapi.util.Pair; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.codegen.AsmUtil; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; +import com.intellij.openapi.util.Pair +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.ArrayList +import java.util.HashSet -public class BoxedBasicValue extends BasicValue { - private final Set associatedInsns = new HashSet(); - private final Set> unboxingWithCastInsns = new HashSet>(); - private final AbstractInsnNode boxingInsn; - private final Set associatedVariables = new HashSet(); - private final Set mergedWith = new HashSet(); - private final Type primitiveType; - private final ProgressionIteratorBasicValue progressionIterator; - private boolean isSafeToRemove = true; +class BoxedBasicValue( + boxedType: Type, + val boxingInsn: AbstractInsnNode, + val progressionIterator: ProgressionIteratorBasicValue? +) : BasicValue(boxedType) { + private val associatedInsns = HashSet() + private val unboxingWithCastInsns = HashSet>() + private val associatedVariables = HashSet() + private val mergedWith = HashSet() - public BoxedBasicValue( - @NotNull Type boxedType, - @NotNull AbstractInsnNode boxingInsn, - @Nullable ProgressionIteratorBasicValue progressionIterator - ) { - super(boxedType); - this.primitiveType = AsmUtil.unboxType(boxedType); - this.boxingInsn = boxingInsn; - this.progressionIterator = progressionIterator; + val primitiveType: Type = AsmUtil.unboxType(boxedType) + var isSafeToRemove = true; private set + + override fun equals(other: Any?) = + this === other + + fun typeEquals(other: BasicValue) = + other is BoxedBasicValue && type == other.type + + override fun hashCode() = + System.identityHashCode(this) + + fun getAssociatedInsns(): List = + ArrayList(associatedInsns) + + fun addInsn(insnNode: AbstractInsnNode) { + associatedInsns.add(insnNode) } - @Override - public boolean equals(Object o) { - return this == o; + fun addVariableIndex(index: Int) { + associatedVariables.add(index) } - public boolean typeEquals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + fun getVariablesIndexes(): List = + ArrayList(associatedVariables) - BoxedBasicValue that = (BoxedBasicValue) o; - - return getType().equals(that.getType()); + fun addMergedWith(value: BoxedBasicValue) { + mergedWith.add(value) } - @Override - public int hashCode() { - return System.identityHashCode(this); + fun getMergedWith(): Iterable = + mergedWith + + fun markAsUnsafeToRemove() { + isSafeToRemove = false } - public List getAssociatedInsns() { - return new ArrayList(associatedInsns); + fun isDoubleSize() = + primitiveType.size == 2 + + fun isFromProgressionIterator() = + progressionIterator != null + + fun addUnboxingWithCastTo(insn: AbstractInsnNode, type: Type) { + unboxingWithCastInsns.add(Pair.create(insn, type)) } - public void addInsn(AbstractInsnNode insnNode) { - associatedInsns.add(insnNode); - } - - public void addVariableIndex(int index) { - associatedVariables.add(index); - } - - public List getVariablesIndexes() { - return new ArrayList(associatedVariables); - } - - public Type getPrimitiveType() { - return primitiveType; - } - - public void addMergedWith(@NotNull BoxedBasicValue value) { - mergedWith.add(value); - } - - @NotNull - public Iterable getMergedWith() { - return mergedWith; - } - - public void markAsUnsafeToRemove() { - isSafeToRemove = false; - } - - public boolean isSafeToRemove() { - return isSafeToRemove; - } - - public boolean isDoubleSize() { - return getPrimitiveType().getSize() == 2; - } - - @NotNull - public AbstractInsnNode getBoxingInsn() { - return boxingInsn; - } - - public boolean isFromProgressionIterator() { - return progressionIterator != null; - } - - @Nullable - public ProgressionIteratorBasicValue getProgressionIterator() { - return progressionIterator; - } - - public void addUnboxingWithCastTo(@NotNull AbstractInsnNode insn, @NotNull Type type) { - unboxingWithCastInsns.add(Pair.create(insn, type)); - } - - @NotNull - public Set> getUnboxingWithCastInsns() { - return unboxingWithCastInsns; - } + fun getUnboxingWithCastInsns(): Set> = + unboxingWithCastInsns } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt index d21b629c999..879112a4745 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt @@ -16,237 +16,154 @@ package org.jetbrains.kotlin.codegen.optimization.boxing; -import com.google.common.collect.ImmutableSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.codegen.AsmUtil; -import org.jetbrains.kotlin.codegen.RangeCodegenUtil; -import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter; -import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType; -import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.builtins.PrimitiveType; -import org.jetbrains.org.objectweb.asm.Opcodes; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; -import org.jetbrains.org.objectweb.asm.tree.InsnList; -import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode; -import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; +import com.google.common.collect.ImmutableSet +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.RangeCodegenUtil +import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.InsnList +import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode +import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException +import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue +import java.util.* -import java.util.HashMap; -import java.util.List; -import java.util.Map; +open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() { + private val boxingPlaces = HashMap() -public class BoxingInterpreter extends OptimizationBasicInterpreter { - private static final ImmutableSet UNBOXING_METHOD_NAMES; - - static { - UNBOXING_METHOD_NAMES = ImmutableSet.of( - "booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue" - ); + protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue { + val index = insnList.indexOf(insn) + return boxingPlaces.getOrPut(index) { + val boxedBasicValue = BoxedBasicValue(type, insn, progressionIterator) + onNewBoxedValue(boxedBasicValue) + boxedBasicValue + } } + @Throws(AnalyzerException::class) + override fun naryOperation(insn: AbstractInsnNode, values: List): BasicValue? { + val value = super.naryOperation(insn, values) + val firstArg = values.firstOrNull() ?: return value - private final Map boxingPlaces = new HashMap(); - private final InsnList insnList; - - public BoxingInterpreter(InsnList insnList) { - this.insnList = insnList; - } - - @NotNull - protected BasicValue createNewBoxing( - @NotNull AbstractInsnNode insn, @NotNull Type type, - @Nullable ProgressionIteratorBasicValue progressionIterator - ) { - int index = insnList.indexOf(insn); - if (!boxingPlaces.containsKey(index)) { - BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, progressionIterator); - onNewBoxedValue(boxedBasicValue); - boxingPlaces.put(index, boxedBasicValue); - } - - return boxingPlaces.get(index); - } - - @Override - @Nullable - public BasicValue naryOperation(@NotNull AbstractInsnNode insn, @NotNull List values) throws AnalyzerException { - BasicValue value = super.naryOperation(insn, values); - - if (values.isEmpty()) return value; - - BasicValue firstArg = values.get(0); - - if (isBoxing(insn)) { - return createNewBoxing(insn, value.getType(), null); - } - else if (isUnboxing(insn) && - firstArg instanceof BoxedBasicValue) { - onUnboxing(insn, (BoxedBasicValue) firstArg, value.getType()); - } - else if (isIteratorMethodCallOfProgression(insn, values)) { - return new ProgressionIteratorBasicValue( - getValuesTypeOfProgressionClass(firstArg.getType().getInternalName()) - ); - } - else if (isNextMethodCallOfProgressionIterator(insn, values)) { - assert firstArg instanceof ProgressionIteratorBasicValue : "firstArg should be progression iterator"; - - ProgressionIteratorBasicValue progressionIterator = (ProgressionIteratorBasicValue) firstArg; - return createNewBoxing( - insn, - AsmUtil.boxType(progressionIterator.getValuesPrimitiveType()), - progressionIterator - ); - } - else { - // nary operation should be a method call or multinewarray - // arguments for multinewarray could be only numeric - // so if there are boxed values in args, it's not a case of multinewarray - for (BasicValue arg : values) { - if (arg instanceof BoxedBasicValue) { - onMethodCallWithBoxedValue((BoxedBasicValue) arg); + return when { + isBoxing(insn) -> { + createNewBoxing(insn, value.type, null) + } + isUnboxing(insn) && firstArg is BoxedBasicValue -> { + onUnboxing(insn, firstArg, value.type) + value + } + isIteratorMethodCallOfProgression(insn, values) -> { + ProgressionIteratorBasicValue(getValuesTypeOfProgressionClass(firstArg.type.internalName)) + } + isNextMethodCallOfProgressionIterator(insn, values) -> { + val progressionIterator = firstArg as? ProgressionIteratorBasicValue + ?: throw AssertionError("firstArg should be progression iterator") + createNewBoxing(insn, AsmUtil.boxType(progressionIterator.valuesPrimitiveType), progressionIterator) + } + else -> { + // N-ary operation should be a method call or multinewarray. + // Arguments for multinewarray could be only numeric, + // so if there are boxed values in args, it's not a case of multinewarray. + for (arg in values) { + if (arg is BoxedBasicValue) { + onMethodCallWithBoxedValue(arg) + } } + value } } - - return value; } - private static boolean isWrapperClassNameOrNumber(@NotNull String internalClassName) { - return isWrapperClassName(internalClassName) || internalClassName.equals(Type.getInternalName(Number.class)); - } + @Throws(AnalyzerException::class) + override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? = + if (insn.opcode == Opcodes.CHECKCAST && isExactValue(value)) + value + else + super.unaryOperation(insn, value) - private static boolean isWrapperClassName(@NotNull String internalClassName) { - return JvmPrimitiveType.isWrapperClassName( - buildFqNameByInternal(internalClassName) - ); - } + protected open fun isExactValue(value: BasicValue) = + value is ProgressionIteratorBasicValue || + value is BoxedBasicValue || + value.type != null && isProgressionClass(value.type.internalName) - @NotNull - private static FqName buildFqNameByInternal(@NotNull String internalClassName) { - return new FqName(Type.getObjectType(internalClassName).getClassName()); - } + override fun merge(v: BasicValue, w: BasicValue) = + when { + v == BasicValue.UNINITIALIZED_VALUE || w == BasicValue.UNINITIALIZED_VALUE -> { + BasicValue.UNINITIALIZED_VALUE + } + v is BoxedBasicValue && v.typeEquals(w) -> { + onMergeSuccess(v, w as BoxedBasicValue) + v + } + else -> { + if (v is BoxedBasicValue) { + onMergeFail(v) + } + if (w is BoxedBasicValue) { + onMergeFail(w) + } + super.merge(v, w) + } + } - private static boolean isUnboxing(@NotNull AbstractInsnNode insn) { - if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) return false; + protected open fun onNewBoxedValue(value: BoxedBasicValue) {} + protected open fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {} + protected open fun onMethodCallWithBoxedValue(value: BoxedBasicValue) {} + protected open fun onMergeFail(value: BoxedBasicValue) {} + protected open fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) {} - MethodInsnNode methodInsn = (MethodInsnNode) insn; + companion object { + private val UNBOXING_METHOD_NAMES = + ImmutableSet.of("booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue") - return isWrapperClassNameOrNumber(methodInsn.owner) && isUnboxingMethodName(methodInsn.name); - } + private fun isWrapperClassNameOrNumber(internalClassName: String) = + isWrapperClassName(internalClassName) || internalClassName == Type.getInternalName(Number::class.java) - private static boolean isUnboxingMethodName(@NotNull String name) { - return UNBOXING_METHOD_NAMES.contains(name); - } + private fun isWrapperClassName(internalClassName: String) = + JvmPrimitiveType.isWrapperClassName(buildFqNameByInternal(internalClassName)) - private static boolean isBoxing(@NotNull AbstractInsnNode insn) { - if (insn.getOpcode() != Opcodes.INVOKESTATIC) return false; + private fun buildFqNameByInternal(internalClassName: String) = + FqName(Type.getObjectType(internalClassName).className) - MethodInsnNode node = (MethodInsnNode) insn; + private fun isUnboxing(insn: AbstractInsnNode) = + insn.opcode == Opcodes.INVOKEVIRTUAL && run { + val methodInsn = insn as MethodInsnNode + isWrapperClassNameOrNumber(methodInsn.owner) && isUnboxingMethodName(methodInsn.name) + } - return isWrapperClassName(node.owner) && "valueOf".equals(node.name) && - Type.getMethodDescriptor( - Type.getObjectType(node.owner), - AsmUtil.unboxType(Type.getObjectType(node.owner)) - ).equals(node.desc); - } + private fun isUnboxingMethodName(name: String) = + UNBOXING_METHOD_NAMES.contains(name) - private static boolean isNextMethodCallOfProgressionIterator( - @NotNull AbstractInsnNode insn, @NotNull List values - ) { - return (insn.getOpcode() == Opcodes.INVOKEINTERFACE && - values.get(0) instanceof ProgressionIteratorBasicValue && - "next".equals(((MethodInsnNode) insn).name)); - } + private fun isBoxing(insn: AbstractInsnNode) = + insn.opcode == Opcodes.INVOKESTATIC && run { + val methodInsn = insn as MethodInsnNode + isWrapperClassName(methodInsn.owner) && methodInsn.name == "valueOf" && run { + val ownerType = Type.getObjectType(methodInsn.owner) + methodInsn.desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType)) + } + } - private static boolean isIteratorMethodCallOfProgression( - @NotNull AbstractInsnNode insn, @NotNull List values - ) { - return (insn.getOpcode() == Opcodes.INVOKEINTERFACE && - values.get(0).getType() != null && - isProgressionClass(values.get(0).getType().getInternalName()) && - "iterator".equals(((MethodInsnNode) insn).name)); - } + private fun isNextMethodCallOfProgressionIterator(insn: AbstractInsnNode, values: kotlin.collections.List) = + insn.opcode == Opcodes.INVOKEINTERFACE && + values[0] is ProgressionIteratorBasicValue && + (insn as MethodInsnNode).name == "next" - private static boolean isProgressionClass(String internalClassName) { - return RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName)); - } + private fun isIteratorMethodCallOfProgression(insn: AbstractInsnNode, values: kotlin.collections.List) = + insn.opcode == Opcodes.INVOKEINTERFACE && run { + val firstArgType = values[0].type + firstArgType != null && isProgressionClass(firstArgType.internalName) && "iterator" == (insn as MethodInsnNode).name + } - /** - * e.g. for "kotlin/IntRange" it returns "Int" - * - * @param progressionClassInternalName - * @return - * @throws java.lang.AssertionError if progressionClassInternalName is not progression class internal name - */ - @NotNull - private static String getValuesTypeOfProgressionClass(String progressionClassInternalName) { - PrimitiveType type = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType( - buildFqNameByInternal(progressionClassInternalName) - ); - - assert type != null : "type should be not null"; - - return type.getTypeName().asString(); - } - - @Override - public BasicValue unaryOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.CHECKCAST && isExactValue(value)) { - return value; - } - - return super.unaryOperation(insn, value); - } - - protected boolean isExactValue(@NotNull BasicValue value) { - return value instanceof ProgressionIteratorBasicValue || - value instanceof BoxedBasicValue || - (value.getType() != null && isProgressionClass(value.getType().getInternalName())); - } - - @Override - @NotNull - public BasicValue merge(@NotNull BasicValue v, @NotNull BasicValue w) { - if (v == BasicValue.UNINITIALIZED_VALUE || w == BasicValue.UNINITIALIZED_VALUE) { - return BasicValue.UNINITIALIZED_VALUE; - } - - if (v instanceof BoxedBasicValue && ((BoxedBasicValue) v).typeEquals(w)) { - onMergeSuccess((BoxedBasicValue) v, (BoxedBasicValue) w); - return v; - } - - if (v instanceof BoxedBasicValue) { - onMergeFail((BoxedBasicValue) v); - } - - if (w instanceof BoxedBasicValue) { - onMergeFail((BoxedBasicValue) w); - } - - return super.merge(v, w); - } - - protected void onNewBoxedValue(@NotNull BoxedBasicValue value) { - - } - - protected void onUnboxing(@NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value, @NotNull Type resultType) { - - } - - protected void onMethodCallWithBoxedValue(@NotNull BoxedBasicValue value) { - - } - - protected void onMergeFail(@NotNull BoxedBasicValue value) { - - } - - protected void onMergeSuccess(@NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w) { + private fun isProgressionClass(internalClassName: String) = + RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName)) + private fun getValuesTypeOfProgressionClass(progressionClassInternalName: String) = + RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))?.let { type -> + type.typeName.asString() + } ?: error("type should be not null") } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt index 6f8efcf21df..239b8427fbc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt @@ -16,163 +16,129 @@ package org.jetbrains.kotlin.codegen.optimization.boxing; -import com.google.common.collect.ImmutableSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.org.objectweb.asm.Opcodes; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; -import org.jetbrains.org.objectweb.asm.tree.InsnList; -import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode; -import org.jetbrains.org.objectweb.asm.tree.VarInsnNode; -import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; +import com.google.common.collect.ImmutableSet +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.InsnList +import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode +import org.jetbrains.org.objectweb.asm.tree.VarInsnNode +import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException +import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue -class RedundantBoxingInterpreter extends BoxingInterpreter { - private static final ImmutableSet PERMITTED_OPERATIONS_OPCODES = ImmutableSet.of( - Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF - ); +internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterpreter(insnList) { - private static final ImmutableSet PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER = ImmutableSet.of( - Type.BYTE, Type.SHORT, Type.INT, Type.FLOAT, Type.LONG, Type.DOUBLE - ); + val candidatesBoxedValues = RedundantBoxedValuesCollection() - private final RedundantBoxedValuesCollection values = new RedundantBoxedValuesCollection(); + @Throws(AnalyzerException::class) + override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? { + processOperationWithBoxedValue(value1, insn) + processOperationWithBoxedValue(value2, insn) - public RedundantBoxingInterpreter(InsnList insnList) { - super(insnList); + return super.binaryOperation(insn, value1, value2) } - @Override - public BasicValue binaryOperation( - @NotNull AbstractInsnNode insn, - @NotNull BasicValue value1, - @NotNull BasicValue value2 - ) throws AnalyzerException { - - processOperationWithBoxedValue(value1, insn); - processOperationWithBoxedValue(value2, insn); - - return super.binaryOperation(insn, value1, value2); - } - - @Override - public BasicValue ternaryOperation( - @NotNull AbstractInsnNode insn, - @NotNull BasicValue value1, @NotNull BasicValue value2, @NotNull BasicValue value3 - ) throws AnalyzerException { - + @Throws(AnalyzerException::class) + override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? { // in a valid code only aastore could happen with boxed value - processOperationWithBoxedValue(value3, insn); + processOperationWithBoxedValue(value3, insn) - return super.ternaryOperation(insn, value1, value2, value3); + return super.ternaryOperation(insn, value1, value2, value3) } - @Nullable - @Override - public BasicValue unaryOperation( - @NotNull AbstractInsnNode insn, @NotNull BasicValue value - ) throws AnalyzerException { + @Throws(AnalyzerException::class) + override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? { + if ((insn.opcode == Opcodes.CHECKCAST || insn.opcode == Opcodes.INSTANCEOF) && value is BoxedBasicValue) { + val typeInsn = insn as TypeInsnNode - if ((insn.getOpcode() == Opcodes.CHECKCAST || insn.getOpcode() == Opcodes.INSTANCEOF) && - value instanceof BoxedBasicValue) { - TypeInsnNode typeInsn = (TypeInsnNode) insn; - - if (!isSafeCast((BoxedBasicValue) value, typeInsn.desc)) { - markValueAsDirty((BoxedBasicValue) value); + if (!isSafeCast(value, typeInsn.desc)) { + markValueAsDirty(value) } } - processOperationWithBoxedValue(value, insn); + processOperationWithBoxedValue(value, insn) - return super.unaryOperation(insn, value); + return super.unaryOperation(insn, value) } - private static boolean isSafeCast(@NotNull BoxedBasicValue value, @NotNull String targetInternalName) { - if (targetInternalName.equals(Type.getInternalName(Object.class))) return true; - - if (targetInternalName.equals(Type.getInternalName(Number.class))) { - return PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains( - value.getPrimitiveType().getSort() - ); + @Throws(AnalyzerException::class) + override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue { + if (value is BoxedBasicValue && insn.opcode === Opcodes.ASTORE) { + value.addVariableIndex((insn as VarInsnNode).`var`) } - return value.getType().getInternalName().equals(targetInternalName); + processOperationWithBoxedValue(value, insn) + + return super.copyOperation(insn, value) } - @Override - @NotNull - public BasicValue copyOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException { - if (value instanceof BoxedBasicValue && insn.getOpcode() == Opcodes.ASTORE) { - ((BoxedBasicValue) value).addVariableIndex(((VarInsnNode) insn).var); - } - - processOperationWithBoxedValue(value, insn); - - return super.copyOperation(insn, value); + fun processPopInstruction(insnNode: AbstractInsnNode, value: BasicValue) { + processOperationWithBoxedValue(value, insnNode) } - public void processPopInstruction(@NotNull AbstractInsnNode insnNode, @NotNull BasicValue value) { - processOperationWithBoxedValue(value, insnNode); + override fun onNewBoxedValue(value: BoxedBasicValue) { + candidatesBoxedValues.add(value) } - @Override - protected void onNewBoxedValue(@NotNull BoxedBasicValue value) { - values.add(value); - } - - @Override - protected void onUnboxing( - @NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value, @NotNull Type resultType - ) { - if (value.getPrimitiveType().equals(resultType)) { - addAssociatedInsn(value, insn); + override fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) { + if (value.primitiveType == resultType) { + addAssociatedInsn(value, insn) } else { - value.addUnboxingWithCastTo(insn, resultType); + value.addUnboxingWithCastTo(insn, resultType) } } - @Override - protected void onMethodCallWithBoxedValue(@NotNull BoxedBasicValue value) { - markValueAsDirty(value); + override fun onMethodCallWithBoxedValue(value: BoxedBasicValue) { + markValueAsDirty(value) } - @Override - protected void onMergeFail(@NotNull BoxedBasicValue v) { - markValueAsDirty(v); + override fun onMergeFail(value: BoxedBasicValue) { + markValueAsDirty(value) } - @Override - protected void onMergeSuccess( - @NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w - ) { - values.merge(v, w); + override fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) { + candidatesBoxedValues.merge(v, w) } - private void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) { - if (value instanceof BoxedBasicValue) { - if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) { - markValueAsDirty((BoxedBasicValue) value); + private fun processOperationWithBoxedValue(value: BasicValue?, insnNode: AbstractInsnNode) { + if (value is BoxedBasicValue) { + if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) { + markValueAsDirty(value) } else { - addAssociatedInsn((BoxedBasicValue) value, insnNode); + addAssociatedInsn(value, insnNode) } } } - private void markValueAsDirty(@NotNull BoxedBasicValue value) { - values.remove(value); + private fun markValueAsDirty(value: BoxedBasicValue) { + candidatesBoxedValues.remove(value) } - private static void addAssociatedInsn(@NotNull BoxedBasicValue value, @NotNull AbstractInsnNode insn) { - if (value.isSafeToRemove()) { - value.addInsn(insn); + companion object { + private val PERMITTED_OPERATIONS_OPCODES = + ImmutableSet.of(Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF) + + private val PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER = + ImmutableSet.of(Type.BYTE, Type.SHORT, Type.INT, Type.FLOAT, Type.LONG, Type.DOUBLE) + + private fun isSafeCast(value: BoxedBasicValue, targetInternalName: String) = + when (targetInternalName) { + Type.getInternalName(Any::class.java) -> + true + Type.getInternalName(Number::class.java) -> { + PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains( + value.primitiveType.sort) + } + else -> + value.type.internalName.equals(targetInternalName) + } + + private fun addAssociatedInsn(value: BoxedBasicValue, insn: AbstractInsnNode) { + if (value.isSafeToRemove) { + value.addInsn(insn) + } } } - - @NotNull - public RedundantBoxedValuesCollection getCandidatesBoxedValues() { - return values; - } -} +} \ No newline at end of file