Correct the argument types of the StringBuilder.append

Modified AsmUtil to generate calls to more specific append methods
in the StringBuilder class in order to save computation time and make
less temporary objects.

Also adds unit-test to verify that the append(Object) method was
invoked 0 times while the append(String) 3 times

Signed-off-by: Laszlo Hornyak <laszlo.hornyak@gmail.com>
This commit is contained in:
Laszlo Hornyak
2014-05-12 21:07:47 +02:00
committed by Alexander Udalov
parent 34e8cae89e
commit 9dec0fb779
5 changed files with 73 additions and 5 deletions
@@ -52,6 +52,7 @@ import java.util.Set;
import static org.jetbrains.jet.codegen.JvmCodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
import static org.jetbrains.jet.lang.resolve.java.mapping.PrimitiveTypesUtil.asmTypeForPrimitive;
@@ -68,6 +69,13 @@ public class AsmUtil {
KotlinBuiltIns.getInstance().getChar()
);
private static final Set<Type> STRING_BUILDER_OBJECT_APPEND_ARG_TYPES = Sets.newHashSet(
getType(String.class),
getType(StringBuilder.class),
getType(StringBuffer.class),
getType(CharSequence.class)
);
private static final int NO_FLAG_LOCAL = 0;
public static final int NO_FLAG_PACKAGE_PRIVATE = 0;
@@ -308,11 +316,25 @@ public class AsmUtil {
return type;
}
private static Type stringValueOfOrStringBuilderAppendType(Type type) {
private static Type stringValueOfType(Type type) {
int sort = type.getSort();
return sort == Type.OBJECT || sort == Type.ARRAY
? AsmTypeConstants.OBJECT_TYPE
: sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
? AsmTypeConstants.OBJECT_TYPE
: sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
}
private static Type stringBuilderAppendType(Type type) {
switch (type.getSort()) {
case Type.OBJECT:
return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : AsmTypeConstants.OBJECT_TYPE;
case Type.ARRAY:
return AsmTypeConstants.OBJECT_TYPE;
case Type.BYTE:
case Type.SHORT:
return Type.INT_TYPE;
default:
return type;
}
}
public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) {
@@ -374,12 +396,12 @@ public class AsmUtil {
}
public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
type = stringValueOfOrStringBuilderAppendType(type);
type = stringBuilderAppendType(type);
v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
}
public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
Type type = stringValueOfOrStringBuilderAppendType(receiverType);
Type type = stringValueOfType(receiverType);
receiver.put(type, v);
v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
return StackValue.onStack(JAVA_STRING_TYPE);
@@ -0,0 +1,10 @@
// KT-5016 wrong StringBuilder append method invoked
class kt5016 {
fun f1(name : String) : String {
return "Hello $name!"
}
}
// 0 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/Object;\)Ljava/lang/StringBuilder
// 3 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/String;\)Ljava/lang/StringBuilder
// 1 INVOKEVIRTUAL java/lang/StringBuilder.toString
@@ -0,0 +1,11 @@
// KT-5016 wrong StringBuilder append method invoked
class kt5016int {
fun f1(num : Int) : String {
return "Hello to all the $num!"
}
}
// 0 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/Object;\)Ljava/lang/StringBuilder
// 2 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/String;\)Ljava/lang/StringBuilder
// 1 INVOKEVIRTUAL java/lang/StringBuilder.append \(I\)Ljava/lang/StringBuilder
// 1 INVOKEVIRTUAL java/lang/StringBuilder.toString
@@ -0,0 +1,10 @@
// KT-5016 wrong StringBuilder append method invoked
class kt5016intOrNull {
fun f1(num : Int?) : String {
return "Hello to all the $num!"
}
}
// 1 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/Object;\)Ljava/lang/StringBuilder
// 2 INVOKEVIRTUAL java/lang/StringBuilder.append \(Ljava/lang/String;\)Ljava/lang/StringBuilder
// 1 INVOKEVIRTUAL java/lang/StringBuilder.toString
@@ -107,6 +107,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest("compiler/testData/codegen/bytecodeText/kt2887.kt");
}
@TestMetadata("kt5016.kt")
public void testKt5016() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/kt5016.kt");
}
@TestMetadata("kt5016int.kt")
public void testKt5016int() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/kt5016int.kt");
}
@TestMetadata("kt5016intOrNull.kt")
public void testKt5016intOrNull() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/kt5016intOrNull.kt");
}
@TestMetadata("noVolatileAnnotation.kt")
public void testNoVolatileAnnotation() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/noVolatileAnnotation.kt");