Changed strategy from enumeration of unsafe operations to permitted + INSTANCEOF added

This commit is contained in:
Denis Zharkov
2014-07-08 15:25:50 +04:00
committed by Alexander Udalov
parent 69d8d07a05
commit a412a96ff3
2 changed files with 41 additions and 33 deletions
@@ -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 {
@@ -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);
}
}