blob: ac4be8c3b23182f3e44ee642fdb506aa5dd2d972 [file] [log] [blame]
// Copyright (c) 2022, 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 static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugEntry;
import com.android.tools.r8.graph.DexDebugEntryBuilder;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class Regress216178582Test extends TestBase {
static final String EXPECTED = StringUtils.lines("Hello world!");
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
public Regress216178582Test(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void test() throws Exception {
Path out =
testForR8(parameters.getBackend())
.addInnerClasses(Regress216178582Test.class)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(TestClass.class)
.addKeepAttributeLineNumberTable()
.addOptionsModification(o -> o.testing.forcePcBasedEncoding = true)
.compile()
.inspect(
inspector -> {
DexEncodedMethod method =
inspector.clazz(TestClass.class).mainMethod().getMethod();
DexCode code = method.getCode().asDexCode();
if (parameters
.getApiLevel()
.isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport())) {
assertNull(code.getDebugInfo());
return;
}
assertTrue(code.getDebugInfo().isPcBasedInfo());
// Force convert the PC info to events.
code.setDebugInfo(DexDebugInfo.convertToEventBased(code, inspector.getFactory()));
List<DexDebugEntry> entries =
new DexDebugEntryBuilder(method, inspector.getFactory()).build();
Iterator<DexDebugEntry> it = entries.iterator();
int pc = 0;
for (Instruction instruction : code.instructions) {
if (instruction.canThrow()) {
DexDebugEntry next = it.next();
assertEquals(
"Invalid entry "
+ next
+ " at pc "
+ StringUtils.hexString(pc, 2)
+ ", in:\n"
+ method.codeToString(),
pc,
next.address);
}
pc += instruction.getSize();
}
})
.writeToZip();
testForD8(parameters.getBackend())
.addProgramFiles(out)
.setMinApi(parameters.getApiLevel())
.addOptionsModification(o -> o.testing.forceJumboStringProcessing = true)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
static class TestClass {
// Use synchronized which will require prolog and epilog of monitor instructions.
// These have small sizes and debug event entries which hit a PC between instructions showing
// that the event stream is built incorrectly when processing jumbo strings.
public static synchronized void main(String[] args) {
System.out.println("Hello world!");
}
}
}