Changed strategy from enumeration of unsafe operations to permitted + INSTANCEOF added
This commit is contained in:
committed by
Alexander Udalov
parent
69d8d07a05
commit
a412a96ff3
+9
-13
@@ -29,17 +29,9 @@ 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> UNSAFE_OPERATIONS_OPCODES;
|
||||
|
||||
static {
|
||||
ImmutableSet.Builder<Integer> unsafeOperationsOpcodesBuilder = ImmutableSet.builder();
|
||||
unsafeOperationsOpcodesBuilder.add(
|
||||
Opcodes.AASTORE, Opcodes.PUTFIELD, Opcodes.PUTSTATIC, Opcodes.ARETURN,
|
||||
Opcodes.IFNONNULL, Opcodes.IFNULL, Opcodes.IF_ACMPEQ, Opcodes.IF_ACMPNE
|
||||
);
|
||||
|
||||
UNSAFE_OPERATIONS_OPCODES = unsafeOperationsOpcodesBuilder.build();
|
||||
}
|
||||
private static final ImmutableSet<Integer> PERMITTED_OPERATIONS_OPCODES = ImmutableSet.of(
|
||||
Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF
|
||||
);
|
||||
|
||||
private final RedundantBoxedValuesCollection values = new RedundantBoxedValuesCollection();
|
||||
|
||||
@@ -78,7 +70,8 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
@NotNull AbstractInsnNode insn, @NotNull BasicValue value
|
||||
) throws AnalyzerException {
|
||||
|
||||
if (insn.getOpcode() == Opcodes.CHECKCAST && value instanceof BoxedBasicValue) {
|
||||
if ((insn.getOpcode() == Opcodes.CHECKCAST || insn.getOpcode() == Opcodes.INSTANCEOF) &&
|
||||
value instanceof BoxedBasicValue) {
|
||||
TypeInsnNode typeInsn = (TypeInsnNode) insn;
|
||||
|
||||
if (!isSafeCast((BoxedBasicValue) value, typeInsn.desc)) {
|
||||
@@ -114,6 +107,9 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
return super.copyOperation(insn, value);
|
||||
}
|
||||
|
||||
public void processPopInstruction(@NotNull AbstractInsnNode insnNode, @NotNull BasicValue value) {
|
||||
processOperationWithBoxedValue(value, insnNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewBoxedValue(@NotNull BoxedBasicValue value) {
|
||||
@@ -151,7 +147,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
|
||||
private void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) {
|
||||
if (value instanceof BoxedBasicValue) {
|
||||
if (UNSAFE_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
|
||||
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
|
||||
markValueAsDirty((BoxedBasicValue) value);
|
||||
}
|
||||
else {
|
||||
|
||||
+32
-20
@@ -44,6 +44,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
new Analyzer<BasicValue>(interpreter),
|
||||
internalClassName, node
|
||||
);
|
||||
interpretPopInstructionsForBoxedValues(interpreter, node, frames);
|
||||
|
||||
RedundantBoxedValuesCollection valuesToOptimize = interpreter.getCandidatesBoxedValues();
|
||||
|
||||
@@ -55,12 +56,32 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
|
||||
|
||||
adaptInstructionsForBoxedValues(node, frames, valuesToOptimize);
|
||||
adaptInstructionsForBoxedValues(node, valuesToOptimize);
|
||||
}
|
||||
|
||||
super.transform(internalClassName, node);
|
||||
}
|
||||
|
||||
private static void interpretPopInstructionsForBoxedValues(
|
||||
@NotNull RedundantBoxingInterpreter interpreter,
|
||||
@NotNull MethodNode node,
|
||||
@NotNull Frame<BasicValue>[] frames
|
||||
) {
|
||||
for (int i = 0; i < node.instructions.size(); i++) {
|
||||
AbstractInsnNode insn = node.instructions.get(i);
|
||||
if ((insn.getOpcode() != Opcodes.POP && insn.getOpcode() != Opcodes.POP2) || frames[i] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1);
|
||||
interpreter.processPopInstruction(insn, top);
|
||||
|
||||
if (top.getSize() == 1 && insn.getOpcode() == Opcodes.POP2) {
|
||||
interpreter.processPopInstruction(insn, frames[i].getStack(frames[i].getStackSize() - 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeValuesClashingWithVariables(
|
||||
@NotNull RedundantBoxedValuesCollection values,
|
||||
@NotNull MethodNode node,
|
||||
@@ -206,31 +227,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValues(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames, @NotNull RedundantBoxedValuesCollection values
|
||||
@NotNull MethodNode node,
|
||||
@NotNull RedundantBoxedValuesCollection values
|
||||
) {
|
||||
addPopInstructionsForBoxedValues(node, frames);
|
||||
|
||||
for (BoxedBasicValue value : values) {
|
||||
adaptInstructionsForBoxedValue(node, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addPopInstructionsForBoxedValues(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
|
||||
) {
|
||||
for (int i = 0; i < node.instructions.size(); i++) {
|
||||
AbstractInsnNode insn = node.instructions.get(i);
|
||||
if (insn.getOpcode() != Opcodes.POP || frames[i] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicValue top = frames[i].getStack(frames[i].getStackSize() - 1);
|
||||
if (top instanceof BoxedBasicValue && ((BoxedBasicValue) top).isSafeToRemove()) {
|
||||
((BoxedBasicValue) top).addInsn(node.instructions.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
adaptBoxingInstruction(node, value);
|
||||
|
||||
@@ -320,7 +324,15 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
)
|
||||
);
|
||||
break;
|
||||
case Opcodes.INSTANCEOF:
|
||||
node.instructions.insertBefore(
|
||||
insn,
|
||||
new InsnNode(isDoubleSize ? Opcodes.POP2 : Opcodes.POP)
|
||||
);
|
||||
node.instructions.set(insn, new InsnNode(Opcodes.ICONST_1));
|
||||
break;
|
||||
default:
|
||||
// CHECKCAST or unboxing-method call
|
||||
node.instructions.remove(insn);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user