dealing with ranges
This commit is contained in:
committed by
Alexander Udalov
parent
ee87b11723
commit
ed445f6488
+21
-2
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization.boxing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
@@ -28,15 +30,18 @@ import java.util.Set;
|
||||
|
||||
public class BoxedBasicValue extends BasicValue {
|
||||
private final Set<AbstractInsnNode> associatedInsns = new HashSet<AbstractInsnNode>();
|
||||
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 RangeIteratorBasicValue numberIterator;
|
||||
private boolean isSafeToRemove = true;
|
||||
|
||||
public BoxedBasicValue(Type boxedType, AbstractInsnNode insnNode) {
|
||||
public BoxedBasicValue(Type boxedType, AbstractInsnNode boxingInsn, @Nullable RangeIteratorBasicValue numberIterator) {
|
||||
super(boxedType);
|
||||
this.primitiveType = AsmUtil.unboxType(boxedType);
|
||||
associatedInsns.add(insnNode);
|
||||
this.boxingInsn = boxingInsn;
|
||||
this.numberIterator = numberIterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,4 +116,18 @@ public class BoxedBasicValue extends BasicValue {
|
||||
public boolean isDoubleSize() {
|
||||
return getPrimitiveType().getSize() == 2;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AbstractInsnNode getBoxingInsn() {
|
||||
return boxingInsn;
|
||||
}
|
||||
|
||||
public boolean isFromNumberIterator() {
|
||||
return numberIterator != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RangeIteratorBasicValue getNumberIterator() {
|
||||
return numberIterator;
|
||||
}
|
||||
}
|
||||
|
||||
+86
-22
@@ -35,6 +35,26 @@ 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")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. for "kotlin/IntRange" it returns "Int"
|
||||
*
|
||||
* @param progressionClassInternalName
|
||||
* @return
|
||||
*/
|
||||
private static String getValuesTypePartOfProgressionClass(String progressionClassInternalName) {
|
||||
progressionClassInternalName = progressionClassInternalName.substring("kotlin/".length());
|
||||
|
||||
int cutAtTheEnd = (progressionClassInternalName.endsWith("Progression")) ? "Progression".length() : "Range".length();
|
||||
return progressionClassInternalName.substring(0, progressionClassInternalName.length() - cutAtTheEnd);
|
||||
}
|
||||
|
||||
private static final ImmutableSet<String> wrappersClassNames;
|
||||
|
||||
static {
|
||||
@@ -47,13 +67,6 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
wrappersClassNames = wrappersClassesBuilder.build();
|
||||
}
|
||||
|
||||
private final Map<Integer, BoxedBasicValue> boxingPlaces = new HashMap<Integer, BoxedBasicValue>();
|
||||
private final InsnList insnList;
|
||||
|
||||
BoxingInterpreter(InsnList insnList) {
|
||||
this.insnList = insnList;
|
||||
}
|
||||
|
||||
private static boolean isWrapperClassName(@NotNull String owner) {
|
||||
return wrappersClassNames.contains(owner);
|
||||
}
|
||||
@@ -86,27 +99,70 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return isWrapperClassName(methodInsnNode.owner) && methodInsnNode.name.equals("valueOf");
|
||||
}
|
||||
|
||||
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()) &&
|
||||
((MethodInsnNode) insn).name.equals("iterator"));
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
private final Map<Integer, BoxedBasicValue> boxingPlaces = new HashMap<Integer, BoxedBasicValue>();
|
||||
private final InsnList insnList;
|
||||
|
||||
BoxingInterpreter(InsnList insnList) {
|
||||
this.insnList = insnList;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private BoxedBasicValue createNewBoxing(
|
||||
@NotNull AbstractInsnNode insn, @NotNull Type type, @Nullable RangeIteratorBasicValue numberIterator
|
||||
) {
|
||||
int index = insnList.indexOf(insn);
|
||||
if (!boxingPlaces.containsKey(index)) {
|
||||
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, numberIterator);
|
||||
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 (isBoxing(insn)) {
|
||||
int index = insnList.indexOf(insn);
|
||||
if (!boxingPlaces.containsKey(index)) {
|
||||
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(value.getType(), insn);
|
||||
onNewBoxedValue(boxedBasicValue);
|
||||
boxingPlaces.put(index, boxedBasicValue);
|
||||
}
|
||||
|
||||
return boxingPlaces.get(index);
|
||||
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);
|
||||
}
|
||||
else if (isIteratorMethodCallOfProgression(insn, values)) {
|
||||
return new RangeIteratorBasicValue(
|
||||
getValuesTypePartOfProgressionClass(values.get(0).getType().getInternalName())
|
||||
);
|
||||
}
|
||||
else if (isNextMethodCallOfProgressionIterator(insn, values)) {
|
||||
RangeIteratorBasicValue numberIterator = (RangeIteratorBasicValue) values.get(0);
|
||||
return createNewBoxing(
|
||||
insn,
|
||||
AsmUtil.boxType(numberIterator.getValuesPrimitiveType()),
|
||||
numberIterator
|
||||
);
|
||||
}
|
||||
else {
|
||||
for (BasicValue arg : values) {
|
||||
if (arg instanceof BoxedBasicValue) {
|
||||
@@ -118,10 +174,15 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static boolean isExactValue(@NotNull BasicValue value) {
|
||||
return value instanceof RangeIteratorBasicValue ||
|
||||
value instanceof BoxedBasicValue ||
|
||||
(value.getType() != null && isProgressionClass(value.getType().getInternalName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BasicValue unaryOperation(@NotNull AbstractInsnNode insn, @NotNull BasicValue value) throws AnalyzerException {
|
||||
if (insn.getOpcode() == Opcodes.CHECKCAST && value instanceof BoxedBasicValue) {
|
||||
if (insn.getOpcode() == Opcodes.CHECKCAST && isExactValue(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -132,16 +193,16 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
@NotNull
|
||||
public BasicValue merge(@NotNull BasicValue v, @NotNull BasicValue w) {
|
||||
if (v instanceof BoxedBasicValue && ((BoxedBasicValue) v).typeEquals(w)) {
|
||||
((BoxedBasicValue) v).mergeWith((BoxedBasicValue) w);
|
||||
onMergeSuccess((BoxedBasicValue) v, (BoxedBasicValue) w);
|
||||
return v;
|
||||
}
|
||||
|
||||
if (v instanceof BoxedBasicValue) {
|
||||
if (v instanceof BoxedBasicValue && w != BasicValue.UNINITIALIZED_VALUE) {
|
||||
onMergeFail((BoxedBasicValue) v);
|
||||
v = new BasicValue(v.getType());
|
||||
}
|
||||
|
||||
if (w instanceof BoxedBasicValue) {
|
||||
if (w instanceof BoxedBasicValue && v != BasicValue.UNINITIALIZED_VALUE) {
|
||||
onMergeFail((BoxedBasicValue) w);
|
||||
w = new BasicValue(w.getType());
|
||||
}
|
||||
@@ -149,7 +210,6 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return super.merge(v, w);
|
||||
}
|
||||
|
||||
|
||||
protected void onNewBoxedValue(@NotNull BoxedBasicValue value) {
|
||||
|
||||
}
|
||||
@@ -165,4 +225,8 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
protected void onMergeFail(@NotNull BoxedBasicValue value) {
|
||||
|
||||
}
|
||||
|
||||
protected void onMergeSuccess(@NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization.boxing;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unexpected type " + valuesTypeName);
|
||||
}
|
||||
|
||||
private final Type valuesPrimitiveType;
|
||||
private final String valuesPrimitiveTypeName;
|
||||
|
||||
public RangeIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
|
||||
super(Type.getObjectType("kotlin/" + valuesPrimitiveTypeName + "Iterator"));
|
||||
this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName);
|
||||
this.valuesPrimitiveTypeName = valuesPrimitiveTypeName;
|
||||
}
|
||||
|
||||
public Type getValuesPrimitiveType() {
|
||||
return valuesPrimitiveType;
|
||||
}
|
||||
|
||||
public String getValuesPrimitiveTypeName() {
|
||||
return valuesPrimitiveTypeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
RangeIteratorBasicValue value = (RangeIteratorBasicValue) o;
|
||||
|
||||
if (!valuesPrimitiveType.equals(value.valuesPrimitiveType)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNextMethodName() {
|
||||
return "next" + getValuesPrimitiveTypeName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getNextMethodDesc() {
|
||||
return "()" + getValuesPrimitiveType().getDescriptor();
|
||||
}
|
||||
}
|
||||
+7
@@ -138,6 +138,13 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
|
||||
markValueAsDirty(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMergeSuccess(
|
||||
@NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w
|
||||
) {
|
||||
v.mergeWith(w);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<BoxedBasicValue> getCandidatesBoxedValues() {
|
||||
return candidatesBoxedValues;
|
||||
|
||||
+32
-2
@@ -50,7 +50,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
adaptLocalVariableTableForBoxedValues(node, frames);
|
||||
|
||||
int[] remapping = variablesRemapping(valuesToOptimize, node);
|
||||
int[] remapping = buildVariablesRemapping(valuesToOptimize, node);
|
||||
applyVariablesRemapping(node, remapping);
|
||||
|
||||
adaptInstructionsForBoxedValues(node, frames, valuesToOptimize);
|
||||
@@ -206,7 +206,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static int[] variablesRemapping(@NotNull Iterable<BoxedBasicValue> values, @NotNull MethodNode node) {
|
||||
private static int[] buildVariablesRemapping(@NotNull Iterable<BoxedBasicValue> values, @NotNull MethodNode node) {
|
||||
Set<Integer> longTypesVars = new HashSet<Integer>();
|
||||
for (BoxedBasicValue value : values) {
|
||||
if (value.getPrimitiveType().getSize() == 2) {
|
||||
@@ -271,11 +271,41 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
adaptBoxingInstruction(node, value);
|
||||
|
||||
for (AbstractInsnNode insn : value.getAssociatedInsns()) {
|
||||
adaptInstruction(node, insn, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
if (!value.isFromNumberIterator()) {
|
||||
node.instructions.remove(value.getBoxingInsn());
|
||||
}
|
||||
else {
|
||||
RangeIteratorBasicValue iterator = value.getNumberIterator();
|
||||
assert iterator != null : "iterator should not be null because isFromNumberIterator returns true";
|
||||
|
||||
//add checkcast to kotlin/<T>Iterator before next() call
|
||||
node.instructions.insertBefore(
|
||||
value.getBoxingInsn(),
|
||||
new TypeInsnNode(Opcodes.CHECKCAST, iterator.getType().getInternalName())
|
||||
);
|
||||
|
||||
//invoke concrete method (kotlin/<T>iteraror.next<T>())
|
||||
node.instructions.set(
|
||||
value.getBoxingInsn(),
|
||||
new MethodInsnNode(
|
||||
Opcodes.INVOKEVIRTUAL,
|
||||
iterator.getType().getInternalName(),
|
||||
iterator.getNextMethodName(),
|
||||
iterator.getNextMethodDesc(),
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptInstruction(
|
||||
@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user