Converting optimization.boxing to Kotlin: convert & simplify

This commit is contained in:
Dmitry Petrov
2016-03-03 11:11:35 +03:00
parent 0555464a3b
commit 2ecb8896cc
3 changed files with 260 additions and 424 deletions
@@ -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<AbstractInsnNode> associatedInsns = new HashSet<AbstractInsnNode>();
private final Set<Pair<AbstractInsnNode, Type>> unboxingWithCastInsns = new HashSet<Pair<AbstractInsnNode, Type>>();
private final AbstractInsnNode boxingInsn;
private final Set<Integer> associatedVariables = new HashSet<Integer>();
private final Set<BoxedBasicValue> mergedWith = new HashSet<BoxedBasicValue>();
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<AbstractInsnNode>()
private val unboxingWithCastInsns = HashSet<Pair<AbstractInsnNode, Type>>()
private val associatedVariables = HashSet<Int>()
private val mergedWith = HashSet<BoxedBasicValue>()
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<AbstractInsnNode> =
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<Int> =
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<BoxedBasicValue> =
mergedWith
fun markAsUnsafeToRemove() {
isSafeToRemove = false
}
public List<AbstractInsnNode> getAssociatedInsns() {
return new ArrayList<AbstractInsnNode>(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<Integer> getVariablesIndexes() {
return new ArrayList<Integer>(associatedVariables);
}
public Type getPrimitiveType() {
return primitiveType;
}
public void addMergedWith(@NotNull BoxedBasicValue value) {
mergedWith.add(value);
}
@NotNull
public Iterable<BoxedBasicValue> 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<Pair<AbstractInsnNode, Type>> getUnboxingWithCastInsns() {
return unboxingWithCastInsns;
}
fun getUnboxingWithCastInsns(): Set<Pair<AbstractInsnNode, Type>> =
unboxingWithCastInsns
}
@@ -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<Int, BoxedBasicValue>()
public class BoxingInterpreter extends OptimizationBasicInterpreter {
private static final ImmutableSet<String> 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>): BasicValue? {
val value = super.naryOperation(insn, values)
val firstArg = values.firstOrNull() ?: return value
private final Map<Integer, BoxedBasicValue> boxingPlaces = new HashMap<Integer, BoxedBasicValue>();
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<? extends BasicValue> 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<? extends BasicValue> 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<? extends BasicValue> 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<BasicValue>) =
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<BasicValue>) =
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")
}
}
@@ -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<Integer> 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<Integer> 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;
}
}
}