| // Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 | package jdk17.ir.optimize.interfaces; | 
 |  | 
 | import static org.junit.Assert.assertEquals; | 
 |  | 
 | import com.android.tools.r8.TestBase; | 
 | import com.android.tools.r8.TestParameters; | 
 | import com.android.tools.r8.TestParametersCollection; | 
 | import com.android.tools.r8.ToolHelper; | 
 | import com.android.tools.r8.utils.codeinspector.CodeInspector; | 
 | import com.android.tools.r8.utils.codeinspector.InstructionSubject; | 
 | import java.io.Serializable; | 
 | import java.lang.reflect.InvocationTargetException; | 
 | import java.lang.reflect.Method; | 
 | import org.junit.Test; | 
 | import org.junit.runner.RunWith; | 
 | import org.junit.runners.Parameterized; | 
 | import org.junit.runners.Parameterized.Parameter; | 
 | import org.junit.runners.Parameterized.Parameters; | 
 |  | 
 | // This test is also present for base test module and JDK-21 to demonstrate the different javac | 
 | // byte code. | 
 | @RunWith(Parameterized.class) | 
 | public class CastWithMultipleBoundsJavacBytecodeTest extends TestBase { | 
 |  | 
 |   @Parameter(0) | 
 |   public TestParameters parameters; | 
 |  | 
 |   @Parameters(name = "{0}") | 
 |   public static TestParametersCollection data() { | 
 |     return getTestParameters().withAllRuntimesAndApiLevels().build(); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testR8JavacCode() throws Exception { | 
 |     parameters.assumeIsOrSimulateNoneRuntime(); | 
 |     // javac from JDK-17 generates the following code for getLambda with three checkcasts to | 
 |     // the two interface types and then to the static return type: | 
 |     // | 
 |     // static java.io.Serializable getLambda(); | 
 |     //   descriptor: ()Ljava/io/Serializable; | 
 |     //   flags: (0x0008) ACC_STATIC | 
 |     //   Code: | 
 |     //     stack=1, locals=0, args_size=0 | 
 |     //        0: invokedynamic #7,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable; | 
 |     //        5: checkcast     #11                 // class java/io/Serializable | 
 |     //        8: checkcast     #13                 // class java/lang/Runnable | 
 |     //       11: checkcast     #11                 // class java/io/Serializable | 
 |     //       14: areturn | 
 |     assertEquals( | 
 |         3, | 
 |         new CodeInspector(ToolHelper.getClassFileForTestClass(TestClass.class)) | 
 |             .clazz(TestClass.class) | 
 |             .uniqueMethodWithOriginalName("getLambda") | 
 |             .streamInstructions() | 
 |             .filter(InstructionSubject::isCheckCast) | 
 |             .count()); | 
 |   } | 
 |  | 
 |   @Test | 
 |   public void testR8() throws Exception { | 
 |     testForR8(parameters.getBackend()) | 
 |         .addInnerClassesAndStrippedOuter(getClass()) | 
 |         .addKeepMainRule(TestClass.class) | 
 |         .setMinApi(parameters) | 
 |         .addKeepMainRule(TestClass.class) | 
 |         .run(parameters.getRuntime(), TestClass.class); | 
 |   } | 
 |  | 
 |   static class TestClass { | 
 |     static void invokeLambda(Object o) | 
 |         throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { | 
 |       Method runMethod = o.getClass().getMethod("run"); | 
 |       runMethod.invoke(o); | 
 |     } | 
 |  | 
 |     static Serializable getLambda() { | 
 |       return (Runnable & Serializable) () -> System.out.println("base lambda"); | 
 |     } | 
 |  | 
 |     public static void main(String[] args) throws Exception { | 
 |       invokeLambda(getLambda()); | 
 |     } | 
 |   } | 
 | } |