|  | // Copyright (c) 2018, 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 com.android.tools.r8.cf; | 
|  |  | 
|  | import static org.junit.Assert.assertEquals; | 
|  |  | 
|  | import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer; | 
|  | import com.android.tools.r8.CompilationMode; | 
|  | import com.android.tools.r8.R8; | 
|  | import com.android.tools.r8.R8Command; | 
|  | import com.android.tools.r8.ToolHelper; | 
|  | import com.android.tools.r8.ToolHelper.ProcessResult; | 
|  | import com.android.tools.r8.cf.code.CfInstruction; | 
|  | import com.android.tools.r8.cf.code.CfInvokeDynamic; | 
|  | import com.android.tools.r8.graph.CfCode; | 
|  | import com.android.tools.r8.graph.DexEncodedMethod; | 
|  | import com.android.tools.r8.origin.Origin; | 
|  | import com.android.tools.r8.utils.AndroidApp; | 
|  | import com.android.tools.r8.utils.AndroidAppConsumers; | 
|  | import com.android.tools.r8.utils.codeinspector.CodeInspector; | 
|  | import java.nio.file.Path; | 
|  | import java.util.Collections; | 
|  | import java.util.List; | 
|  | import org.junit.Assert; | 
|  | import org.junit.Rule; | 
|  | import org.junit.Test; | 
|  | import org.junit.rules.TemporaryFolder; | 
|  |  | 
|  | public class LambdaTestRunner { | 
|  |  | 
|  | private static final Class<?> CLASS = LambdaTest.class; | 
|  | private static final String METHOD = "main"; | 
|  |  | 
|  | @Rule | 
|  | public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest(); | 
|  |  | 
|  | @Test | 
|  | public void test() throws Exception { | 
|  | // Test that the InvokeDynamic instruction in LambdaTest.main() | 
|  | // is not modified by the R8 compilation. | 
|  | // First, extract the InvokeDynamic instruction from the input class. | 
|  | byte[] inputClass = ToolHelper.getClassAsBytes(CLASS); | 
|  | AndroidApp inputApp = | 
|  | AndroidApp.builder().addClassProgramData(inputClass, Origin.unknown()).build(); | 
|  | CfInvokeDynamic insnInput = findFirstInMethod(inputApp); | 
|  | Assert.assertNotNull("No CfInvokeDynamic found in input", insnInput); | 
|  | // Compile with R8 and extract the InvokeDynamic instruction from the output class. | 
|  | AndroidAppConsumers appBuilder = new AndroidAppConsumers(); | 
|  | Path outPath = temp.getRoot().toPath().resolve("out.jar"); | 
|  | R8.run( | 
|  | R8Command.builder() | 
|  | .setMode(CompilationMode.DEBUG) | 
|  | .setDisableTreeShaking(true) | 
|  | .setDisableMinification(true) | 
|  | .addLibraryFiles(ToolHelper.getJava8RuntimeJar()) | 
|  | .setProgramConsumer(appBuilder.wrapClassFileConsumer(new ArchiveConsumer(outPath))) | 
|  | .addClassProgramData(inputClass, Origin.unknown()) | 
|  | .build()); | 
|  | AndroidApp outputApp = appBuilder.build(); | 
|  | CfInvokeDynamic insnOutput = findFirstInMethod(outputApp); | 
|  | Assert.assertNotNull("No CfInvokeDynamic found in output", insnOutput); | 
|  | // Check that the InvokeDynamic instruction is not modified. | 
|  | assertEquals(print(insnInput), print(insnOutput)); | 
|  | // Check that execution gives the same output. | 
|  | ProcessResult inputResult = | 
|  | ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getName()); | 
|  | ProcessResult outputResult = ToolHelper.runJava(outPath, CLASS.getName()); | 
|  | assertEquals(inputResult.toString(), outputResult.toString()); | 
|  | } | 
|  |  | 
|  | private static CfInvokeDynamic findFirstInMethod(AndroidApp app) throws Exception { | 
|  | String returnType = "void"; | 
|  | CodeInspector inspector = new CodeInspector(app); | 
|  | List<String> args = Collections.singletonList(String[].class.getTypeName()); | 
|  | DexEncodedMethod method = inspector.clazz(CLASS).method(returnType, METHOD, args).getMethod(); | 
|  | CfCode code = method.getCode().asCfCode(); | 
|  | for (CfInstruction instruction : code.getInstructions()) { | 
|  | if (instruction instanceof CfInvokeDynamic) { | 
|  | return (CfInvokeDynamic) instruction; | 
|  | } | 
|  | } | 
|  | return null; | 
|  | } | 
|  |  | 
|  | private static String print(CfInstruction instruction) { | 
|  | CfPrinter printer = new CfPrinter(); | 
|  | instruction.print(printer); | 
|  | return printer.toString(); | 
|  | } | 
|  |  | 
|  | } |