| // 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.CompilationMode; | |
| import com.android.tools.r8.D8; | |
| import com.android.tools.r8.D8Command; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.code.Instruction; | |
| import com.android.tools.r8.code.Nop; | |
| import com.android.tools.r8.utils.AndroidApiLevel; | |
| import com.android.tools.r8.utils.AndroidApp; | |
| import com.android.tools.r8.utils.AndroidAppConsumers; | |
| import java.util.Arrays; | |
| import org.junit.Test; | |
| public class Regress111337896TestRunner extends DebugInfoTestBase { | |
| @Test | |
| public void test() throws Exception { | |
| Class clazz = Regress111337896Test.class; | |
| // Check the regression test is valid code. | |
| String expected = "aok"; | |
| assertEquals(expected, runOnJava(clazz)); | |
| for (AndroidApiLevel minApi : Arrays.asList(AndroidApiLevel.L, AndroidApiLevel.M)) { | |
| for (CompilationMode mode : CompilationMode.values()) { | |
| AndroidAppConsumers appSink = new AndroidAppConsumers(); | |
| D8.run( | |
| D8Command.builder() | |
| .addProgramFiles(ToolHelper.getClassFileForTestClass(clazz)) | |
| .setProgramConsumer(appSink.wrapDexIndexedConsumer(null)) | |
| .setMode(mode) | |
| .setMinApiLevel(minApi.getLevel()) | |
| .build()); | |
| AndroidApp app = appSink.build(); | |
| assertEquals(expected, runOnArt(app, clazz.getCanonicalName())); | |
| // Check that the compiled output contains a nop to workaround the issue. | |
| // We can't really check much else as this only reproduces on some physical x86_64 devices. | |
| check(inspectMethod(app, clazz, "void", "regress111337896"), mode, minApi); | |
| } | |
| } | |
| } | |
| private void check(DebugInfoInspector info, CompilationMode mode, AndroidApiLevel minApi) { | |
| info.checkStartLine(12); | |
| assertEquals(1, info.checkLineExists(18)); | |
| int nopsFound = 0; | |
| for (Instruction instruction : info.getMethod().getCode().asDexCode().instructions) { | |
| if (instruction instanceof Nop) { | |
| nopsFound++; | |
| } | |
| } | |
| if (mode == CompilationMode.DEBUG) { | |
| // In debug mode a nop is used to preserve line 21. | |
| info.checkLineExists(21); | |
| assertEquals(1, nopsFound); | |
| } else { | |
| // Release mode will have removed the line. | |
| info.checkNoLine(21); | |
| // In release mode the workaround will have inserted a nop if below M. | |
| int expectedNops = minApi.getLevel() < AndroidApiLevel.M.getLevel() ? 1 : 0; | |
| assertEquals(expectedNops, nopsFound); | |
| } | |
| } | |
| } |