Fixes after review
This commit is contained in:
committed by
Alexander Udalov
parent
d604b5de79
commit
b1a54a424e
@@ -115,6 +115,16 @@ public class RangeCodegenUtil {
|
||||
return map.get(DescriptorUtils.getFqNameSafe(declarationDescriptor));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PrimitiveType getPrimitiveRangeOrProgressionElementType(@NotNull FqName rangeOrProgressionName) {
|
||||
PrimitiveType result = RANGE_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
|
||||
return result != null ? result : PROGRESSION_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
|
||||
}
|
||||
|
||||
public static boolean isRangeOrProgression(@NotNull FqName className) {
|
||||
return getPrimitiveRangeOrProgressionElementType(className) != null;
|
||||
}
|
||||
|
||||
public static boolean isOptimizableRangeTo(CallableDescriptor rangeTo) {
|
||||
if ("rangeTo".equals(rangeTo.getName().asString())) {
|
||||
if (isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) {
|
||||
|
||||
+5
-6
@@ -30,7 +30,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
private final MethodTransformer methodTransformer = new RedundantNullCheckMethodTransformer(
|
||||
private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer(
|
||||
new RedundantBoxingMethodTransformer(null)
|
||||
);
|
||||
|
||||
@@ -62,15 +62,14 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
super.visitEnd();
|
||||
|
||||
if (methodNode.instructions.size() > 0) {
|
||||
methodTransformer.transform("fake", methodNode);
|
||||
MAIN_METHOD_TRANSFORMER.transform("fake", methodNode);
|
||||
}
|
||||
|
||||
methodNode.accept(new EndIgnoringMethodVisitorDecorator(OptimizationUtils.API, delegate));
|
||||
|
||||
/*
|
||||
In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||
So we just do it here
|
||||
*/
|
||||
|
||||
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
|
||||
// So we just do it here
|
||||
if (methodNode.instructions.size() == 0) {
|
||||
List<LocalVariableNode> localVariables = methodNode.localVariables;
|
||||
// visits local variables
|
||||
|
||||
+11
-7
@@ -34,14 +34,18 @@ public class BoxedBasicValue extends BasicValue {
|
||||
private final Set<Integer> associatedVariables = new HashSet<Integer>();
|
||||
private final Set<BoxedBasicValue> mergedWith = new HashSet<BoxedBasicValue>();
|
||||
private final Type primitiveType;
|
||||
private final RangeIteratorBasicValue numberIterator;
|
||||
private final ProgressionIteratorBasicValue progressionIterator;
|
||||
private boolean isSafeToRemove = true;
|
||||
|
||||
public BoxedBasicValue(Type boxedType, AbstractInsnNode boxingInsn, @Nullable RangeIteratorBasicValue numberIterator) {
|
||||
public BoxedBasicValue(
|
||||
@NotNull Type boxedType,
|
||||
@NotNull AbstractInsnNode boxingInsn,
|
||||
@Nullable ProgressionIteratorBasicValue progressionIterator
|
||||
) {
|
||||
super(boxedType);
|
||||
this.primitiveType = AsmUtil.unboxType(boxedType);
|
||||
this.boxingInsn = boxingInsn;
|
||||
this.numberIterator = numberIterator;
|
||||
this.progressionIterator = progressionIterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,12 +126,12 @@ public class BoxedBasicValue extends BasicValue {
|
||||
return boxingInsn;
|
||||
}
|
||||
|
||||
public boolean isFromNumberIterator() {
|
||||
return numberIterator != null;
|
||||
public boolean isFromProgressionIterator() {
|
||||
return progressionIterator != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RangeIteratorBasicValue getNumberIterator() {
|
||||
return numberIterator;
|
||||
public ProgressionIteratorBasicValue getProgressionIterator() {
|
||||
return progressionIterator;
|
||||
}
|
||||
}
|
||||
|
||||
+60
-45
@@ -20,8 +20,11 @@ import com.google.common.collect.ImmutableSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.jet.codegen.RangeCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.optimization.common.OptimizationBasicInterpreter;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
@@ -35,54 +38,58 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
private static boolean isProgressionClass(String internalName) {
|
||||
return internalName.startsWith("kotlin/") && (
|
||||
internalName.endsWith("Progression") ||
|
||||
internalName.endsWith("Range")
|
||||
private static final ImmutableSet<String> UNBOXING_METHOD_NAMES;
|
||||
|
||||
static {
|
||||
UNBOXING_METHOD_NAMES = ImmutableSet.of(
|
||||
"booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isProgressionClass(String internalClassName) {
|
||||
return RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName));
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. for "kotlin/IntRange" it returns "Int"
|
||||
*
|
||||
* @param progressionClassInternalName
|
||||
* @return
|
||||
* @throws java.lang.AssertionError if progressionClassInternalName is not progression class internal name
|
||||
*/
|
||||
private static String getValuesTypePartOfProgressionClass(String progressionClassInternalName) {
|
||||
progressionClassInternalName = progressionClassInternalName.substring("kotlin/".length());
|
||||
@NotNull
|
||||
private static String getValuesTypeOfProgressionClass(String progressionClassInternalName) {
|
||||
PrimitiveType type = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(
|
||||
buildFqNameByInternal(progressionClassInternalName)
|
||||
);
|
||||
|
||||
int cutAtTheEnd = (progressionClassInternalName.endsWith("Progression")) ? "Progression".length() : "Range".length();
|
||||
return progressionClassInternalName.substring(0, progressionClassInternalName.length() - cutAtTheEnd);
|
||||
assert type != null : "type should be not null";
|
||||
|
||||
return type.getTypeName().asString();
|
||||
}
|
||||
|
||||
private static final ImmutableSet<String> wrappersClassNames;
|
||||
|
||||
static {
|
||||
ImmutableSet.Builder<String> wrappersClassesBuilder = ImmutableSet.builder();
|
||||
|
||||
for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) {
|
||||
wrappersClassesBuilder.add(AsmUtil.internalNameByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()));
|
||||
}
|
||||
|
||||
wrappersClassNames = wrappersClassesBuilder.build();
|
||||
private static boolean isWrapperClassName(@NotNull String internalClassName) {
|
||||
return JvmPrimitiveType.isWrapperClassName(
|
||||
buildFqNameByInternal(internalClassName)
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean isWrapperClassName(@NotNull String owner) {
|
||||
return wrappersClassNames.contains(owner);
|
||||
@NotNull
|
||||
private static FqName buildFqNameByInternal(@NotNull String internalClassName) {
|
||||
return new FqName(Type.getObjectType(internalClassName).getClassName());
|
||||
}
|
||||
|
||||
private static boolean isWrapperClassNameOrNumber(@NotNull String owner) {
|
||||
return isWrapperClassName(owner) || owner.equals(Type.getInternalName(Number.class));
|
||||
private static boolean isWrapperClassNameOrNumber(@NotNull String internalClassName) {
|
||||
return isWrapperClassName(internalClassName) || internalClassName.equals(Type.getInternalName(Number.class));
|
||||
}
|
||||
|
||||
private static boolean isUnboxingMethodName(@NotNull String name) {
|
||||
return name.endsWith("Value");
|
||||
return UNBOXING_METHOD_NAMES.contains(name);
|
||||
}
|
||||
|
||||
private static boolean isUnboxing(@NotNull AbstractInsnNode insn) {
|
||||
if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) {
|
||||
return false;
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) return false;
|
||||
|
||||
MethodInsnNode methodInsn = (MethodInsnNode) insn;
|
||||
|
||||
@@ -90,13 +97,11 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
}
|
||||
|
||||
private static boolean isBoxing(@NotNull AbstractInsnNode insn) {
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
|
||||
return false;
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC) return false;
|
||||
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
|
||||
|
||||
return isWrapperClassName(methodInsnNode.owner) && methodInsnNode.name.equals("valueOf");
|
||||
return isWrapperClassName(methodInsnNode.owner) && "valueOf".equals(methodInsnNode.name);
|
||||
}
|
||||
|
||||
private static boolean isIteratorMethodCallOfProgression(
|
||||
@@ -105,31 +110,32 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return (insn.getOpcode() == Opcodes.INVOKEINTERFACE &&
|
||||
values.get(0).getType() != null &&
|
||||
isProgressionClass(values.get(0).getType().getInternalName()) &&
|
||||
((MethodInsnNode) insn).name.equals("iterator"));
|
||||
"iterator".equals(((MethodInsnNode) insn).name));
|
||||
}
|
||||
|
||||
private static boolean isNextMethodCallOfProgressionIterator(
|
||||
@NotNull AbstractInsnNode insn, @NotNull List<? extends BasicValue> values
|
||||
) {
|
||||
return (insn.getOpcode() == Opcodes.INVOKEINTERFACE &&
|
||||
values.get(0) instanceof RangeIteratorBasicValue &&
|
||||
((MethodInsnNode) insn).name.equals("next"));
|
||||
values.get(0) instanceof ProgressionIteratorBasicValue &&
|
||||
"next".equals(((MethodInsnNode) insn).name));
|
||||
}
|
||||
|
||||
private final Map<Integer, BoxedBasicValue> boxingPlaces = new HashMap<Integer, BoxedBasicValue>();
|
||||
private final InsnList insnList;
|
||||
|
||||
BoxingInterpreter(InsnList insnList) {
|
||||
public BoxingInterpreter(InsnList insnList) {
|
||||
this.insnList = insnList;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private BoxedBasicValue createNewBoxing(
|
||||
@NotNull AbstractInsnNode insn, @NotNull Type type, @Nullable RangeIteratorBasicValue numberIterator
|
||||
@NotNull AbstractInsnNode insn, @NotNull Type type,
|
||||
@Nullable ProgressionIteratorBasicValue progressionIterator
|
||||
) {
|
||||
int index = insnList.indexOf(insn);
|
||||
if (!boxingPlaces.containsKey(index)) {
|
||||
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, numberIterator);
|
||||
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, progressionIterator);
|
||||
onNewBoxedValue(boxedBasicValue);
|
||||
boxingPlaces.put(index, boxedBasicValue);
|
||||
}
|
||||
@@ -142,28 +148,37 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
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) &&
|
||||
values.get(0) instanceof BoxedBasicValue &&
|
||||
value.getType().equals(((BoxedBasicValue) values.get(0)).getPrimitiveType())) {
|
||||
onUnboxing((BoxedBasicValue) values.get(0), insn);
|
||||
firstArg instanceof BoxedBasicValue &&
|
||||
value.getType().equals(((BoxedBasicValue) firstArg).getPrimitiveType())) {
|
||||
onUnboxing((BoxedBasicValue) firstArg, insn);
|
||||
}
|
||||
else if (isIteratorMethodCallOfProgression(insn, values)) {
|
||||
return new RangeIteratorBasicValue(
|
||||
getValuesTypePartOfProgressionClass(values.get(0).getType().getInternalName())
|
||||
return new ProgressionIteratorBasicValue(
|
||||
getValuesTypeOfProgressionClass(firstArg.getType().getInternalName())
|
||||
);
|
||||
}
|
||||
else if (isNextMethodCallOfProgressionIterator(insn, values)) {
|
||||
RangeIteratorBasicValue numberIterator = (RangeIteratorBasicValue) values.get(0);
|
||||
assert firstArg instanceof ProgressionIteratorBasicValue : "firstArg should be progression iterator";
|
||||
|
||||
ProgressionIteratorBasicValue progressionIterator = (ProgressionIteratorBasicValue) firstArg;
|
||||
return createNewBoxing(
|
||||
insn,
|
||||
AsmUtil.boxType(numberIterator.getValuesPrimitiveType()),
|
||||
numberIterator
|
||||
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);
|
||||
@@ -175,7 +190,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
}
|
||||
|
||||
private static boolean isExactValue(@NotNull BasicValue value) {
|
||||
return value instanceof RangeIteratorBasicValue ||
|
||||
return value instanceof ProgressionIteratorBasicValue ||
|
||||
value instanceof BoxedBasicValue ||
|
||||
(value.getType() != null && isProgressionClass(value.getType().getInternalName()));
|
||||
}
|
||||
|
||||
+22
-26
@@ -16,41 +16,37 @@
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization.boxing;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
|
||||
|
||||
public class RangeIteratorBasicValue extends BasicValue {
|
||||
private static Type getValuesType(@NotNull String valuesTypeName) {
|
||||
if (valuesTypeName.equals("Byte")) {
|
||||
return Type.BYTE_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Char")) {
|
||||
return Type.CHAR_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Short")) {
|
||||
return Type.SHORT_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Int")) {
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Long")) {
|
||||
return Type.LONG_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Float")) {
|
||||
return Type.FLOAT_TYPE;
|
||||
}
|
||||
if (valuesTypeName.equals("Double")) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
}
|
||||
public class ProgressionIteratorBasicValue extends BasicValue {
|
||||
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
|
||||
|
||||
throw new RuntimeException("Unexpected type " + valuesTypeName);
|
||||
static {
|
||||
VALUES_TYPENAME_TO_TYPE = ImmutableMap.<String, Type>builder().
|
||||
put("Byte", Type.BYTE_TYPE).
|
||||
put("Char", Type.CHAR_TYPE).
|
||||
put("Short", Type.SHORT_TYPE).
|
||||
put("Int", Type.INT_TYPE).
|
||||
put("Long", Type.LONG_TYPE).
|
||||
put("Float", Type.FLOAT_TYPE).
|
||||
put("Double", Type.DOUBLE_TYPE).
|
||||
build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Type getValuesType(@NotNull String valuesTypeName) {
|
||||
Type type = VALUES_TYPENAME_TO_TYPE.get(valuesTypeName);
|
||||
assert type != null : "Unexpected type " + valuesTypeName;
|
||||
return type;
|
||||
}
|
||||
|
||||
private final Type valuesPrimitiveType;
|
||||
private final String valuesPrimitiveTypeName;
|
||||
|
||||
public RangeIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
|
||||
public ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
|
||||
super(Type.getObjectType("kotlin/" + valuesPrimitiveTypeName + "Iterator"));
|
||||
this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName);
|
||||
this.valuesPrimitiveTypeName = valuesPrimitiveTypeName;
|
||||
@@ -70,7 +66,7 @@ public class RangeIteratorBasicValue extends BasicValue {
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
RangeIteratorBasicValue value = (RangeIteratorBasicValue) o;
|
||||
ProgressionIteratorBasicValue value = (ProgressionIteratorBasicValue) o;
|
||||
|
||||
if (!valuesPrimitiveType.equals(value.valuesPrimitiveType)) return false;
|
||||
|
||||
+6
-4
@@ -30,7 +30,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
private static final ImmutableSet<Integer> unsafeOperationsOpcodes;
|
||||
private static final ImmutableSet<Integer> UNSAFE_OPERATIONS_OPCODES;
|
||||
|
||||
static {
|
||||
ImmutableSet.Builder<Integer> unsafeOperationsOpcodesBuilder = ImmutableSet.builder();
|
||||
@@ -39,12 +39,12 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
Opcodes.IFNONNULL, Opcodes.IFNULL, Opcodes.IF_ACMPEQ, Opcodes.IF_ACMPNE
|
||||
);
|
||||
|
||||
unsafeOperationsOpcodes = unsafeOperationsOpcodesBuilder.build();
|
||||
UNSAFE_OPERATIONS_OPCODES = unsafeOperationsOpcodesBuilder.build();
|
||||
}
|
||||
|
||||
private final Set<BoxedBasicValue> candidatesBoxedValues = new HashSet<BoxedBasicValue>();
|
||||
|
||||
RedundantBoxingInterpreter(InsnList insnList) {
|
||||
public RedundantBoxingInterpreter(InsnList insnList) {
|
||||
super(insnList);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
|
||||
private static void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) {
|
||||
if (value instanceof BoxedBasicValue) {
|
||||
if (unsafeOperationsOpcodes.contains(insnNode.getOpcode())) {
|
||||
if (UNSAFE_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
|
||||
markValueAsDirty((BoxedBasicValue) value);
|
||||
}
|
||||
else {
|
||||
@@ -76,6 +76,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
@NotNull BasicValue value2
|
||||
) throws AnalyzerException {
|
||||
|
||||
processOperationWithBoxedValue(value1, insn);
|
||||
processOperationWithBoxedValue(value2, insn);
|
||||
|
||||
return super.binaryOperation(insn, value1, value2);
|
||||
@@ -87,6 +88,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
@NotNull BasicValue value1, @NotNull BasicValue value2, @NotNull BasicValue value3
|
||||
) throws AnalyzerException {
|
||||
|
||||
// in a valid code only aastore could happen with boxed value
|
||||
processOperationWithBoxedValue(value3, insn);
|
||||
|
||||
return super.ternaryOperation(insn, value1, value2, value3);
|
||||
|
||||
+19
-20
@@ -36,27 +36,26 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(@NotNull String owner, @NotNull MethodNode node) {
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode node) {
|
||||
RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions);
|
||||
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(interpreter);
|
||||
|
||||
Frame<BasicValue>[] frames = runAnalyzer(analyzer, owner, node);
|
||||
Frame<BasicValue>[] frames = runAnalyzer(analyzer, internalClassName, node);
|
||||
Set<BoxedBasicValue> valuesToOptimize = filterSafeToRemoveValues(interpreter.getCandidatesBoxedValues());
|
||||
|
||||
if (valuesToOptimize.size() > 0) {
|
||||
if (!valuesToOptimize.isEmpty()) {
|
||||
findValuesClashingWithVariables(node, frames);
|
||||
|
||||
valuesToOptimize = filterSafeToRemoveValues(valuesToOptimize);
|
||||
|
||||
adaptLocalVariableTableForBoxedValues(node, frames);
|
||||
|
||||
int[] remapping = buildVariablesRemapping(valuesToOptimize, node);
|
||||
applyVariablesRemapping(node, remapping);
|
||||
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
|
||||
|
||||
adaptInstructionsForBoxedValues(node, frames, valuesToOptimize);
|
||||
}
|
||||
|
||||
super.transform(owner, node);
|
||||
super.transform(internalClassName, node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -108,12 +107,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
private static void findValuesClashingWithVariables(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
|
||||
) {
|
||||
|
||||
while (findValuesClashingWithVariablesIteration(node, frames)) {
|
||||
while (findValuesClashingWithVariablesPass(node, frames)) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean findValuesClashingWithVariablesIteration(
|
||||
private static boolean findValuesClashingWithVariablesPass(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
|
||||
) {
|
||||
InsnList insnList = node.instructions;
|
||||
@@ -154,7 +153,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
Type usedAsType = null;
|
||||
|
||||
for (int i = from; i <= to; i++) {
|
||||
AbstractInsnNode insn = insnList.get(i);
|
||||
AbstractInsnNode insn = insnList.get(i); //TODO: handle exception?
|
||||
if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == varIndex) {
|
||||
if (frames[i] == null) {
|
||||
return true;
|
||||
@@ -207,21 +206,21 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
@NotNull
|
||||
private static int[] buildVariablesRemapping(@NotNull Iterable<BoxedBasicValue> values, @NotNull MethodNode node) {
|
||||
Set<Integer> longTypesVars = new HashSet<Integer>();
|
||||
Set<Integer> doubleSizedVars = new HashSet<Integer>();
|
||||
for (BoxedBasicValue value : values) {
|
||||
if (value.getPrimitiveType().getSize() == 2) {
|
||||
longTypesVars.addAll(value.getVariablesIndexes());
|
||||
doubleSizedVars.addAll(value.getVariablesIndexes());
|
||||
}
|
||||
}
|
||||
|
||||
node.maxLocals += longTypesVars.size();
|
||||
node.maxLocals += doubleSizedVars.size();
|
||||
int[] remapping = new int[node.maxLocals];
|
||||
for (int i = 0; i < remapping.length; i++) {
|
||||
remapping[i] = i;
|
||||
}
|
||||
|
||||
for (int longVarIndex : longTypesVars) {
|
||||
for (int i = longVarIndex + 1; i < remapping.length; i++) {
|
||||
for (int varIndex : doubleSizedVars) {
|
||||
for (int i = varIndex + 1; i < remapping.length; i++) {
|
||||
remapping[i]++;
|
||||
}
|
||||
}
|
||||
@@ -247,14 +246,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
private static void adaptInstructionsForBoxedValues(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames, @NotNull Set<BoxedBasicValue> values
|
||||
) {
|
||||
collectPopInstructionsForBoxedValues(node, frames);
|
||||
addPopInstructionsForBoxedValues(node, frames);
|
||||
|
||||
for (BoxedBasicValue value : values) {
|
||||
adaptInstructionsForBoxedValue(node, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void collectPopInstructionsForBoxedValues(
|
||||
private static void addPopInstructionsForBoxedValues(
|
||||
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
|
||||
) {
|
||||
for (int i = 0; i < node.instructions.size(); i++) {
|
||||
@@ -279,12 +278,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
if (!value.isFromNumberIterator()) {
|
||||
if (!value.isFromProgressionIterator()) {
|
||||
node.instructions.remove(value.getBoxingInsn());
|
||||
}
|
||||
else {
|
||||
RangeIteratorBasicValue iterator = value.getNumberIterator();
|
||||
assert iterator != null : "iterator should not be null because isFromNumberIterator returns true";
|
||||
ProgressionIteratorBasicValue iterator = value.getProgressionIterator();
|
||||
assert iterator != null : "iterator should not be null because isFromProgressionIterator returns true";
|
||||
|
||||
//add checkcast to kotlin/<T>Iterator before next() call
|
||||
node.instructions.insertBefore(
|
||||
|
||||
+6
-6
@@ -36,22 +36,22 @@ public class RedundantNullCheckMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(@NotNull String owner, @NotNull MethodNode methodNode) {
|
||||
|
||||
while (removeRedundantNullCheck(owner, methodNode)) {
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
|
||||
while (removeRedundantNullCheckPass(internalClassName, methodNode)) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
super.transform(owner, methodNode);
|
||||
super.transform(internalClassName, methodNode);
|
||||
}
|
||||
|
||||
private static boolean removeRedundantNullCheck(@NotNull String owner, @NotNull MethodNode methodNode) {
|
||||
private static boolean removeRedundantNullCheckPass(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
InsnList insnList = methodNode.instructions;
|
||||
Frame<BasicValue>[] frames = runAnalyzer(
|
||||
new Analyzer<BasicValue>(
|
||||
new BoxingInterpreter(insnList)
|
||||
),
|
||||
owner, methodNode
|
||||
internalClassName, methodNode
|
||||
);
|
||||
|
||||
List<AbstractInsnNode> insnsToOptimize = new ArrayList<AbstractInsnNode>();
|
||||
|
||||
+4
-4
@@ -32,20 +32,20 @@ public abstract class MethodTransformer {
|
||||
|
||||
protected static <V extends Value> Frame<V>[] runAnalyzer(
|
||||
@NotNull Analyzer<V> analyzer,
|
||||
@NotNull String owner,
|
||||
@NotNull String internalClassName,
|
||||
@NotNull MethodNode node
|
||||
) {
|
||||
try {
|
||||
return analyzer.analyze(owner, node);
|
||||
return analyzer.analyze(internalClassName, node);
|
||||
}
|
||||
catch (AnalyzerException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void transform(@NotNull String owner, @NotNull MethodNode methodNode) {
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
if (delegate != null) {
|
||||
delegate.transform(owner, methodNode);
|
||||
delegate.transform(internalClassName, methodNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user