| // 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.debuginfo; | |
| 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.ProgramConsumer; | |
| import com.android.tools.r8.R8Command; | |
| import com.android.tools.r8.R8Command.Builder; | |
| import com.android.tools.r8.TestBase; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.ToolHelper.ProcessResult; | |
| import com.android.tools.r8.origin.Origin; | |
| import com.google.common.collect.ImmutableList; | |
| import java.nio.file.Path; | |
| import org.junit.Test; | |
| public class KotlinDebugInfoTestRunner extends TestBase { | |
| private Path buildInput(byte[] clazz, String descriptor) { | |
| Path inputJar = temp.getRoot().toPath().resolve("input.jar"); | |
| ArchiveConsumer inputJarConsumer = new ArchiveConsumer(inputJar); | |
| inputJarConsumer.accept(ByteDataView.of(clazz), descriptor, null); | |
| inputJarConsumer.finished(null); | |
| return inputJar; | |
| } | |
| private Path buildCf(Path inputJar) throws Exception { | |
| Path cfJar = temp.getRoot().toPath().resolve("r8cf.jar"); | |
| build(inputJar, new ArchiveConsumer(cfJar)); | |
| return cfJar; | |
| } | |
| @Test | |
| public void testRingBuffer() throws Exception { | |
| // This test hits the case where we simplify a DebugLocalWrite v'(x) <- v | |
| // with debug use [live: y], and y is written between v and v'. | |
| // In this case we must not move [live: y] to the definition of v, | |
| // since it causes the live range of y to extend to the entry to the first block. | |
| test(KotlinRingBufferDump.dump(), KotlinRingBufferDump.CLASS_NAME); | |
| } | |
| @Test | |
| public void testReflection() throws Exception { | |
| // This test hits the case where we replace a phi(v, v) that has local info | |
| // with v that has no local info. | |
| test(KotlinReflectionDump.dump(), KotlinReflectionDump.CLASS_NAME); | |
| } | |
| @Test | |
| public void testFoo() throws Exception { | |
| test(DebugInfoDump.dump(), DebugInfoDump.CLASS_NAME); | |
| } | |
| public void test(byte[] bytes, String className) throws Exception { | |
| String descriptor = 'L' + className.replace('.', '/') + ';'; | |
| Path inputJar = buildInput(bytes, descriptor); | |
| ProcessResult runInput = ToolHelper.runJava(inputJar, className); | |
| if (0 != runInput.exitCode) { | |
| System.out.println(runInput); | |
| } | |
| assertEquals(0, runInput.exitCode); | |
| Path outCf = buildCf(inputJar); | |
| ProcessResult runCf = ToolHelper.runJava(outCf, className); | |
| assertEquals(runInput.toString(), runCf.toString()); | |
| } | |
| 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); | |
| } | |
| } |