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;
|
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
|
||||||
|
|
||||||
class RedundantBoxingInterpreter extends BoxingInterpreter {
|
class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||||
private static final ImmutableSet<Integer> UNSAFE_OPERATIONS_OPCODES;
|
private static final ImmutableSet<Integer> PERMITTED_OPERATIONS_OPCODES = ImmutableSet.of(
|
||||||
|
Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF
|
||||||
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 final RedundantBoxedValuesCollection values = new RedundantBoxedValuesCollection();
|
private final RedundantBoxedValuesCollection values = new RedundantBoxedValuesCollection();
|
||||||
|
|
||||||
@@ -78,7 +70,8 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
|||||||
@NotNull AbstractInsnNode insn, @NotNull BasicValue value
|
@NotNull AbstractInsnNode insn, @NotNull BasicValue value
|
||||||
) throws AnalyzerException {
|
) 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;
|
TypeInsnNode typeInsn = (TypeInsnNode) insn;
|
||||||
|
|
||||||
if (!isSafeCast((BoxedBasicValue) value, typeInsn.desc)) {
|
if (!isSafeCast((BoxedBasicValue) value, typeInsn.desc)) {
|
||||||
@@ -114,6 +107,9 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
|||||||
return super.copyOperation(insn, value);
|
return super.copyOperation(insn, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void processPopInstruction(@NotNull AbstractInsnNode insnNode, @NotNull BasicValue value) {
|
||||||
|
processOperationWithBoxedValue(value, insnNode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onNewBoxedValue(@NotNull BoxedBasicValue value) {
|
protected void onNewBoxedValue(@NotNull BoxedBasicValue value) {
|
||||||
@@ -151,7 +147,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
|||||||
|
|
||||||
private void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) {
|
private void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) {
|
||||||
if (value instanceof BoxedBasicValue) {
|
if (value instanceof BoxedBasicValue) {
|
||||||
if (UNSAFE_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
|
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
|
||||||
markValueAsDirty((BoxedBasicValue) value);
|
markValueAsDirty((BoxedBasicValue) value);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+32
-20
@@ -44,6 +44,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
|||||||
new Analyzer<BasicValue>(interpreter),
|
new Analyzer<BasicValue>(interpreter),
|
||||||
internalClassName, node
|
internalClassName, node
|
||||||
);
|
);
|
||||||
|
interpretPopInstructionsForBoxedValues(interpreter, node, frames);
|
||||||
|
|
||||||
RedundantBoxedValuesCollection valuesToOptimize = interpreter.getCandidatesBoxedValues();
|
RedundantBoxedValuesCollection valuesToOptimize = interpreter.getCandidatesBoxedValues();
|
||||||
|
|
||||||
@@ -55,12 +56,32 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
|||||||
|
|
||||||
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
|
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
|
||||||
|
|
||||||
adaptInstructionsForBoxedValues(node, frames, valuesToOptimize);
|
adaptInstructionsForBoxedValues(node, valuesToOptimize);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.transform(internalClassName, node);
|
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(
|
private static void removeValuesClashingWithVariables(
|
||||||
@NotNull RedundantBoxedValuesCollection values,
|
@NotNull RedundantBoxedValuesCollection values,
|
||||||
@NotNull MethodNode node,
|
@NotNull MethodNode node,
|
||||||
@@ -206,31 +227,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void adaptInstructionsForBoxedValues(
|
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) {
|
for (BoxedBasicValue value : values) {
|
||||||
adaptInstructionsForBoxedValue(node, value);
|
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) {
|
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||||
adaptBoxingInstruction(node, value);
|
adaptBoxingInstruction(node, value);
|
||||||
|
|
||||||
@@ -320,7 +324,15 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
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:
|
default:
|
||||||
|
// CHECKCAST or unboxing-method call
|
||||||
node.instructions.remove(insn);
|
node.instructions.remove(insn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user