| // 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.debug; | |
| import static org.junit.Assert.assertEquals; | |
| import com.android.tools.r8.ByteDataView; | |
| import com.android.tools.r8.ClassFileConsumer; | |
| import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer; | |
| import com.android.tools.r8.CompilationMode; | |
| import com.android.tools.r8.DexIndexedConsumer; | |
| import com.android.tools.r8.ProgramConsumer; | |
| import com.android.tools.r8.R8Command; | |
| import com.android.tools.r8.R8Command.Builder; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.ToolHelper.DexVm.Version; | |
| import com.android.tools.r8.ToolHelper.ProcessResult; | |
| import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.DebuggeeState; | |
| import com.android.tools.r8.origin.Origin; | |
| import com.google.common.collect.ImmutableList; | |
| import java.nio.file.Path; | |
| import java.util.stream.Stream; | |
| import org.junit.Assume; | |
| import org.junit.Test; | |
| public class IincDebugTestRunner extends DebugTestBase { | |
| @Test | |
| public void compareDifferentRegister() throws Exception { | |
| compareOutput(IincDebugTestDump.dump(1, 2, false)); | |
| } | |
| @Test | |
| public void compareLoadStoreSameRegister() throws Exception { | |
| compareOutput(IincDebugTestDump.dump(1, 1, false)); | |
| } | |
| @Test | |
| public void compareIinc() throws Exception { | |
| compareOutput(IincDebugTestDump.dump(1, 1, true)); | |
| } | |
| @Test | |
| public void stepDifferentRegister() throws Exception { | |
| stepOutput(IincDebugTestDump.dump(1, 2, false)); | |
| } | |
| @Test | |
| public void stepLoadStoreSameRegister() throws Exception { | |
| stepOutput(IincDebugTestDump.dump(1, 1, false)); | |
| } | |
| @Test | |
| public void stepIinc() throws Exception { | |
| stepOutput(IincDebugTestDump.dump(1, 1, true)); | |
| } | |
| private void compareOutput(byte[] clazz) throws Exception { | |
| Path inputJar = buildInput(clazz); | |
| ProcessResult runInput = ToolHelper.runJava(inputJar, IincDebugTestDump.CLASS_NAME); | |
| assertEquals(0, runInput.exitCode); | |
| ProcessResult runCf = ToolHelper.runJava(buildCf(inputJar), IincDebugTestDump.CLASS_NAME); | |
| assertEquals(0, runCf.exitCode); | |
| assertEquals(runInput.toString(), runCf.toString()); | |
| String runDex = | |
| ToolHelper.runArtNoVerificationErrors( | |
| buildDex(inputJar).toString(), IincDebugTestDump.CLASS_NAME); | |
| assertEquals(runInput.stdout, runDex); | |
| } | |
| private void stepOutput(byte[] clazz) throws Exception { | |
| // See verifyStateLocation in DebugTestBase. | |
| Assume.assumeTrue( | |
| "Streaming on Dalvik DEX runtimes has some unknown interference issue", | |
| ToolHelper.getDexVm().getVersion().isAtLeast(Version.V6_0_1)); | |
| Assume.assumeTrue( | |
| "Skipping test " | |
| + testName.getMethodName() | |
| + " because debug tests are not yet supported on Windows", | |
| !ToolHelper.isWindows()); | |
| Path inputJar = buildInput(clazz); | |
| new DebugStreamComparator() | |
| .add("Input", streamDebugTest(new CfDebugTestConfig(inputJar))) | |
| .add("R8/DEX", streamDebugTest(new DexDebugTestConfig(buildDex(inputJar)))) | |
| .add("R8/CF", streamDebugTest(new CfDebugTestConfig(buildCf(inputJar)))) | |
| .compare(); | |
| } | |
| private Stream<DebuggeeState> streamDebugTest(DebugTestConfig config) throws Exception { | |
| return streamDebugTest(config, IincDebugTestDump.CLASS_NAME, ANDROID_FILTER); | |
| } | |
| private Path buildInput(byte[] clazz) { | |
| Path inputJar = temp.getRoot().toPath().resolve("input.jar"); | |
| ArchiveConsumer inputJarConsumer = new ArchiveConsumer(inputJar); | |
| inputJarConsumer.accept(ByteDataView.of(clazz), IincDebugTestDump.DESCRIPTOR, null); | |
| inputJarConsumer.finished(null); | |
| return inputJar; | |
| } | |
| private Path buildDex(Path inputJar) throws Exception { | |
| Path dexJar = temp.getRoot().toPath().resolve("r8dex.jar"); | |
| build(inputJar, new DexIndexedConsumer.ArchiveConsumer(dexJar)); | |
| return dexJar; | |
| } | |
| private Path buildCf(Path inputJar) throws Exception { | |
| Path cfJar = temp.getRoot().toPath().resolve("r8cf.jar"); | |
| build(inputJar, new ArchiveConsumer(cfJar)); | |
| return cfJar; | |
| } | |
| private void build(Path inputJar, ProgramConsumer consumer) throws Exception { | |
| Builder builder = | |
| R8Command.builder() | |
| .setMode(CompilationMode.DEBUG) | |
| .setDisableTreeShaking(true) | |
| .setDisableMinification(true) | |
| .addProguardConfiguration( | |
| ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), Origin.unknown()) | |
| .setProgramConsumer(consumer) | |
| .addProgramFiles(inputJar); | |
| if ((consumer instanceof ClassFileConsumer)) { | |
| builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar()); | |
| } else { | |
| builder.addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm())); | |
| } | |
| ToolHelper.runR8(builder.build(), options -> options.invalidDebugInfoFatal = true); | |
| } | |
| } |