diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/java/com/google/devtools/build/android/desugar/Bug62060793TestDataGenerator.java | 318 | ||||
-rw-r--r-- | test/java/com/google/devtools/build/android/desugar/DesugarLambdaTest.java | 38 |
2 files changed, 356 insertions, 0 deletions
diff --git a/test/java/com/google/devtools/build/android/desugar/Bug62060793TestDataGenerator.java b/test/java/com/google/devtools/build/android/desugar/Bug62060793TestDataGenerator.java new file mode 100644 index 0000000..f6c3c99 --- /dev/null +++ b/test/java/com/google/devtools/build/android/desugar/Bug62060793TestDataGenerator.java @@ -0,0 +1,318 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.android.desugar; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.objectweb.asm.Opcodes.ACC_ABSTRACT; +import static org.objectweb.asm.Opcodes.ACC_FINAL; +import static org.objectweb.asm.Opcodes.ACC_INTERFACE; +import static org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_STATIC; +import static org.objectweb.asm.Opcodes.ACC_SUPER; +import static org.objectweb.asm.Opcodes.ACONST_NULL; +import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.ARETURN; +import static org.objectweb.asm.Opcodes.ASTORE; +import static org.objectweb.asm.Opcodes.BIPUSH; +import static org.objectweb.asm.Opcodes.DCONST_0; +import static org.objectweb.asm.Opcodes.DLOAD; +import static org.objectweb.asm.Opcodes.DUP_X1; +import static org.objectweb.asm.Opcodes.FCONST_0; +import static org.objectweb.asm.Opcodes.FLOAD; +import static org.objectweb.asm.Opcodes.GOTO; +import static org.objectweb.asm.Opcodes.IADD; +import static org.objectweb.asm.Opcodes.ICONST_0; +import static org.objectweb.asm.Opcodes.ICONST_1; +import static org.objectweb.asm.Opcodes.ICONST_2; +import static org.objectweb.asm.Opcodes.ICONST_4; +import static org.objectweb.asm.Opcodes.IFNONNULL; +import static org.objectweb.asm.Opcodes.ILOAD; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.INVOKESTATIC; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.ISTORE; +import static org.objectweb.asm.Opcodes.LCONST_0; +import static org.objectweb.asm.Opcodes.LLOAD; +import static org.objectweb.asm.Opcodes.NEW; +import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.SIPUSH; +import static org.objectweb.asm.Opcodes.SWAP; +import static org.objectweb.asm.Opcodes.V1_8; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * Test data generator for b/62060793. This class creates a special labmda invocation that + * contains *CONST_0 values on stack, which are passed as lambda arguments. + */ +public class Bug62060793TestDataGenerator { + + private static final String CLASS_NAME = + "com/google/devtools/build/android/desugar/testdata/ConstantArgumentsInLambda"; + + private static final String INTERFACE_TYPE_NAME = CLASS_NAME + "$Interface"; + + public static void main(String[] args) throws IOException { + checkArgument( + args.length == 1, + "Usage: %s <output-jar>", + Bug62060793TestDataGenerator.class.getName()); + Path outputJar = Paths.get(args[0]); + + try (ZipOutputStream outZip = + new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(outputJar)))) { + String className = CLASS_NAME + ".class"; + writeToZipFile(outZip, className, createClass()); + String interfaceName = INTERFACE_TYPE_NAME + ".class"; + writeToZipFile(outZip, interfaceName, createInterface()); + } + } + + private static void writeToZipFile(ZipOutputStream outZip, String entryName, byte[] content) + throws IOException { + ZipEntry result = new ZipEntry(entryName); + result.setTime(0L); + outZip.putNextEntry(result); + outZip.write(content); + outZip.closeEntry(); + } + + private static byte[] createClass() { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + cw.visit( + V1_8, ACC_PUBLIC | ACC_SUPER, + CLASS_NAME, + null, "java/lang/Object", null); + + cw.visitInnerClass( + INTERFACE_TYPE_NAME, + CLASS_NAME, + "Interface", + ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); + + cw.visitInnerClass( + "java/lang/invoke/MethodHandles$Lookup", + "java/lang/invoke/MethodHandles", + "Lookup", + ACC_PUBLIC | ACC_FINAL | ACC_STATIC); + + { + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + mv.visitInsn(RETURN); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PRIVATE | ACC_STATIC, + "method", + "(Ljava/lang/String;)Ljava/lang/String;", + null, + null); + mv.visitParameter("str", 0); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(ARETURN); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PRIVATE | ACC_STATIC, + "method", + "(ZCBFDJISLjava/lang/Object;[Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String;", + null, + null); + mv.visitParameter("bool", 0); + mv.visitParameter("c", 0); + mv.visitParameter("b", 0); + mv.visitParameter("f", 0); + mv.visitParameter("d", 0); + mv.visitParameter("l", 0); + mv.visitParameter("i", 0); + mv.visitParameter("s", 0); + mv.visitParameter("o", 0); + mv.visitParameter("array", 0); + mv.visitParameter("str", 0); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 10); + mv.visitMethodInsn( + INVOKESTATIC, + "java/lang/String", + "valueOf", + "(Ljava/lang/Object;)Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, 13); + mv.visitVarInsn(ALOAD, 11); + Label l0 = new Label(); + mv.visitJumpInsn(IFNONNULL, l0); + mv.visitInsn(ICONST_1); + Label l1 = new Label(); + mv.visitJumpInsn(GOTO, l1); + mv.visitLabel(l0); + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {"java/lang/String"}, 0, null); + mv.visitInsn(ICONST_0); + mv.visitLabel(l1); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {Opcodes.INTEGER}); + mv.visitVarInsn(ISTORE, 14); + mv.visitIntInsn(BIPUSH, 91); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", + "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", + "length", "()I", false); + mv.visitInsn(IADD); + mv.visitVarInsn(ALOAD, 13); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", + "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", + "length", "()I", false); + mv.visitInsn(IADD); + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP_X1); + mv.visitInsn(SWAP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", + "<init>", "(I)V", false); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(Z)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(I)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(FLOAD, 3); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(F)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(DLOAD, 4); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(D)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(LLOAD, 6); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(J)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 8); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(I)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(I)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ALOAD, 13); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); + mv.visitVarInsn(ILOAD, 14); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "append", "(Z)Ljava/lang/StringBuilder;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", + "toString", "()Ljava/lang/String;", false); + mv.visitInsn(ARETURN); + mv.visitEnd(); + } + { + mv = cw.visitMethod( + ACC_PUBLIC | ACC_STATIC, + "lambdaWithConstantArguments", + "()L" + INTERFACE_TYPE_NAME + ";", + null, null); + mv.visitCode(); + mv.visitInsn(ICONST_0); + mv.visitInsn(ICONST_1); + mv.visitInsn(ICONST_2); + mv.visitInsn(FCONST_0); + mv.visitInsn(DCONST_0); + mv.visitInsn(LCONST_0); + mv.visitInsn(ICONST_4); + mv.visitIntInsn(SIPUSH, 9); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ACONST_NULL); + mv.visitInvokeDynamicInsn( + "call", + "(ZCBFDJISLjava/lang/Object;[Ljava/lang/Object;)L" + INTERFACE_TYPE_NAME + ";", + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;" + + ")Ljava/lang/invoke/CallSite;", + false), + new Object[] { + Type.getType("(Ljava/lang/String;)Ljava/lang/String;"), + new Handle( + Opcodes.H_INVOKESTATIC, + CLASS_NAME, + "method", + "(ZCBFDJISLjava/lang/Object;[Ljava/lang/Object;Ljava/lang/String;" + + ")Ljava/lang/String;", + false), + Type.getType("(Ljava/lang/String;)Ljava/lang/String;")}); + mv.visitInsn(ARETURN); + mv.visitEnd(); + } + + cw.visitEnd(); + + return cw.toByteArray(); + } + + private static byte[] createInterface() { + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, + INTERFACE_TYPE_NAME, + null, "java/lang/Object", null); + + cw.visitInnerClass( + INTERFACE_TYPE_NAME, + CLASS_NAME, + "Interface", + ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE); + + { + mv = cw.visitMethod( + ACC_PUBLIC | ACC_ABSTRACT, + "call", + "(Ljava/lang/String;)Ljava/lang/String;", + null, + null); + mv.visitParameter("input", 0); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + + } +} diff --git a/test/java/com/google/devtools/build/android/desugar/DesugarLambdaTest.java b/test/java/com/google/devtools/build/android/desugar/DesugarLambdaTest.java new file mode 100644 index 0000000..7c3d7ee --- /dev/null +++ b/test/java/com/google/devtools/build/android/desugar/DesugarLambdaTest.java @@ -0,0 +1,38 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// 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 com.google.devtools.build.android.desugar; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.android.desugar.testdata.ConstantArgumentsInLambda; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests uncommon lambda scenarious. + */ +@RunWith(JUnit4.class) +public class DesugarLambdaTest { + + /** + * Test for b/62060793. Verifies constant lambda arguments that were pushed using *CONST_0 + * instructions. + */ + @Test + public void testCallLambdaWithConstants() throws Exception { + assertThat(ConstantArgumentsInLambda.lambdaWithConstantArguments().call("test")) + .isEqualTo("testfalse\00120.00.0049nulltrue"); + } +} |