blob: 077c7a7bedbe19ab25c70b6f57a492c4aef17fa2 [file] [log] [blame]
// 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();
}
}