Merge "Replace the use of switchmaps with direct use of ordinal."
diff --git a/src/test/debugTestResources/Bridges.java b/src/test/debugTestResources/Bridges.java
new file mode 100644
index 0000000..e1a4380
--- /dev/null
+++ b/src/test/debugTestResources/Bridges.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2017, 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.
+
+public class Bridges {
+
+ interface GenericInterface<T> {
+
+ void get(T t);
+ }
+
+ static class StringImpl implements GenericInterface<String> {
+
+ @Override
+ public void get(String s) {
+ System.out.println(s);
+ }
+ }
+
+ public static void testGenericBridge(GenericInterface<String> obj) {
+ obj.get("Foo");
+ }
+
+ public static void main(String[] args) {
+ testGenericBridge(new StringImpl());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 7f9ecb0..49c0837 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.TestCondition.D8_COMPILER;
import static com.android.tools.r8.TestCondition.R8_COMPILER;
+import static com.android.tools.r8.TestCondition.R8DEBUG_AFTER_D8_COMPILER;
import static com.android.tools.r8.TestCondition.any;
import static com.android.tools.r8.TestCondition.match;
import static com.android.tools.r8.TestCondition.runtimes;
@@ -4653,6 +4654,14 @@
// 1) t04
// java.lang.AssertionError
+ .put("lang.reflect.Field.getLjava_lang_Object.Field_get_A04", match(R8DEBUG_AFTER_D8_COMPILER))
+ // 1) t02
+ // java.lang.AssertionError: expected:<9223372036854775807> but was:<72057594037927935>
+
+ .put("lang.reflect.Field.getLongLjava_lang_Object.Field_getLong_A04", match(R8DEBUG_AFTER_D8_COMPILER))
+ // 1)
+ // java.lang.AssertionError: expected:<9223372036854775807> but was:<72057594037927935>
+
.build(); // end of failuresToTriage
public static final Multimap<String, TestCondition> flakyWithArt =
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index b026dcd..5c5975c 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.utils.ArtErrorParser;
import com.android.tools.r8.utils.ArtErrorParser.ArtErrorInfo;
import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.JarBuilder;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OffOrAuto;
@@ -25,10 +26,10 @@
import com.google.common.collect.Multimap;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
-import com.google.common.io.Files;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -54,7 +55,6 @@
public abstract class R8RunArtTestsTest {
private static final boolean DEX_COMPARE_WITH_DEX_REFERENCE_ON_FAILURE = true;
- private static String[] D8_EXTRA_ARGS = {"--debug"};
private final String name;
private final DexTool toolchain;
@@ -70,7 +70,8 @@
public enum CompilerUnderTest {
D8,
- R8
+ R8,
+ R8DEBUG_AFTER_D8 // refers to the R8/debug step but implies a previous D8 step as well
}
private static final String ART_TESTS_DIR = "tests/art";
@@ -937,13 +938,23 @@
private void executeCompilerUnderTest(
CompilerUnderTest compilerUnderTest, Collection<String> fileNames, String resultPath)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, null);
+ executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, null, null);
}
private void executeCompilerUnderTest(
CompilerUnderTest compilerUnderTest,
Collection<String> fileNames,
String resultPath,
+ CompilationMode compilationMode)
+ throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
+ executeCompilerUnderTest(compilerUnderTest, fileNames, resultPath, compilationMode, null);
+ }
+
+ private void executeCompilerUnderTest(
+ CompilerUnderTest compilerUnderTest,
+ Collection<String> fileNames,
+ String resultPath,
+ CompilationMode mode,
String keepRulesFile)
throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
switch (compilerUnderTest) {
@@ -951,7 +962,7 @@
assert keepRulesFile == null : "Keep-rules file specified for D8.";
D8Command.Builder builder =
D8Command.builder()
- .setMode(CompilationMode.DEBUG)
+ .setMode(mode == null ? CompilationMode.DEBUG : mode)
.addProgramFiles(ListUtils.map(fileNames, Paths::get));
Integer minSdkVersion = needMinSdkVersion.get(name);
if (minSdkVersion != null) {
@@ -964,7 +975,7 @@
case R8: {
R8Command.Builder builder =
R8Command.builder()
- .setMode(CompilationMode.RELEASE)
+ .setMode(mode == null ? CompilationMode.RELEASE : mode)
.setOutputPath(Paths.get(resultPath))
.addProgramFiles(ListUtils.map(fileNames, Paths::get))
.setIgnoreMissingClasses(true);
@@ -1045,10 +1056,15 @@
DexVm dexVm = ToolHelper.getDexVm();
- File resultDir = temp.getRoot();
+ CompilerUnderTest firstCompilerUnderTest =
+ compilerUnderTest == CompilerUnderTest.R8DEBUG_AFTER_D8
+ ? CompilerUnderTest.D8
+ : compilerUnderTest;
+
+ File resultDir = temp.newFolder(firstCompilerUnderTest.toString().toLowerCase() + "-output");
JctfTestSpecifications.Outcome expectedOutcome = JctfTestSpecifications
- .getExpectedOutcome(name, compilerUnderTest, dexVm);
+ .getExpectedOutcome(name, firstCompilerUnderTest, dexVm);
TestSpecification specification = new TestSpecification(name, DexTool.NONE, resultDir,
expectedOutcome == JctfTestSpecifications.Outcome.TIMEOUTS_WITH_ART
|| expectedOutcome == JctfTestSpecifications.Outcome.FLAKY_WITH_ART,
@@ -1116,7 +1132,53 @@
for (File f : allClassFiles) {
fileNames.add(f.getCanonicalPath());
}
- executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getCanonicalPath());
+
+ runJctfTestDoRunOnArt(fileNames,
+ specification,
+ firstCompilerUnderTest,
+ fullClassName,
+ null,
+ dexVm,
+ resultDir);
+
+ // second pass if D8_R8Debug
+ if (compilerUnderTest == CompilerUnderTest.R8DEBUG_AFTER_D8) {
+ List<String> d8OutputFileNames =
+ Files.list(resultDir.toPath())
+ .filter(FileUtils::isDexFile)
+ .map(Path::toString)
+ .collect(Collectors.toList());
+ File r8ResultDir = temp.newFolder("r8-output");
+ expectedOutcome = JctfTestSpecifications
+ .getExpectedOutcome(name, CompilerUnderTest.R8DEBUG_AFTER_D8, dexVm);
+ specification = new TestSpecification(name, DexTool.DX, r8ResultDir,
+ expectedOutcome == JctfTestSpecifications.Outcome.TIMEOUTS_WITH_ART
+ || expectedOutcome == JctfTestSpecifications.Outcome.FLAKY_WITH_ART,
+ expectedOutcome == JctfTestSpecifications.Outcome.FAILS_WITH_ART);
+ if (specification.skipTest) {
+ return;
+ }
+ runJctfTestDoRunOnArt(
+ d8OutputFileNames,
+ specification,
+ CompilerUnderTest.R8,
+ fullClassName,
+ CompilationMode.DEBUG,
+ dexVm,
+ r8ResultDir);
+ }
+ }
+
+ private void runJctfTestDoRunOnArt(
+ Collection<String> fileNames,
+ TestSpecification specification,
+ CompilerUnderTest compilerUnderTest,
+ String fullClassName,
+ CompilationMode mode,
+ DexVm dexVm,
+ File resultDir)
+ throws IOException, ProguardRuleParserException, ExecutionException, CompilationException {
+ executeCompilerUnderTest(compilerUnderTest, fileNames, resultDir.getAbsolutePath(), mode);
if (!ToolHelper.artSupported()) {
return;
@@ -1196,7 +1258,7 @@
if (toolchain == DexTool.NONE) {
File classes = new File(specification.directory, "classes");
inputFiles =
- Files.fileTreeTraverser().breadthFirstTraversal(classes).filter(
+ com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(classes).filter(
(File f) -> !f.isDirectory()).toArray(File.class);
File smali = new File(specification.directory, "smali");
if (smali.exists()) {
@@ -1207,7 +1269,7 @@
File classes2 = new File(specification.directory, "classes2");
if (classes2.exists()) {
inputFiles = ObjectArrays.concat(inputFiles,
- Files.fileTreeTraverser().breadthFirstTraversal(classes2).filter(
+ com.google.common.io.Files.fileTreeTraverser().breadthFirstTraversal(classes2).filter(
(File f) -> !f.isDirectory()).toArray(File.class), File.class);
}
} else {
@@ -1258,7 +1320,7 @@
}
File expectedFile = specification.resolveFile("expected.txt");
- String expected = Files.toString(expectedFile, Charsets.UTF_8);
+ String expected = com.google.common.io.Files.toString(expectedFile, Charsets.UTF_8);
if (specification.failsWithArt) {
thrown.expect(AssertionError.class);
}
@@ -1281,7 +1343,7 @@
if (checkCommand.exists()) {
// Run the Art test custom check command.
File actualFile = temp.newFile();
- Files.asByteSink(actualFile).write(output.getBytes(Charsets.UTF_8));
+ com.google.common.io.Files.asByteSink(actualFile).write(output.getBytes(Charsets.UTF_8));
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(
specification.resolveFile("check").toString(), expectedFile.toString(),
diff --git a/src/test/java/com/android/tools/r8/TestCondition.java b/src/test/java/com/android/tools/r8/TestCondition.java
index ef2eac3..5ffd779 100644
--- a/src/test/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/java/com/android/tools/r8/TestCondition.java
@@ -40,6 +40,8 @@
public static final CompilerSet D8_COMPILER = compilers(CompilerUnderTest.D8);
public static final CompilerSet R8_COMPILER = compilers(CompilerUnderTest.R8);
+ public static final CompilerSet R8DEBUG_AFTER_D8_COMPILER =
+ compilers(CompilerUnderTest.R8DEBUG_AFTER_D8);
private static final ToolSet ANY_TOOL = new ToolSet(EnumSet.allOf(DexTool.class));
private static final CompilerSet ANY_COMPILER =
@@ -107,7 +109,13 @@
}
public boolean test(DexTool dexTool, CompilerUnderTest compilerUnderTest, DexVm dexVm) {
- return dexTools.contains(dexTool) && compilers.contains(compilerUnderTest)
+ // R8DEBUG_AFTER_D8 will be set in the R8 phase of the D8-then-R8 tests. So R8DEBUG_AFTER_D8
+ // must match both with plain R8 and itself.
+ boolean compilerMatches = compilers.contains(compilerUnderTest)
+ || (compilerUnderTest == CompilerUnderTest.R8DEBUG_AFTER_D8
+ && compilers.contains(CompilerUnderTest.R8));
+ return dexTools.contains(dexTool)
+ && compilerMatches
&& dexVms.contains(dexVm);
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index 8f2e9ce..fa7443c 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -15,6 +15,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -29,12 +30,15 @@
import org.apache.harmony.jpda.tests.framework.jdwp.EventPacket;
import org.apache.harmony.jpda.tests.framework.jdwp.Frame.Variable;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands.ReferenceTypeCommandSet;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands.StackFrameCommandSet;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.Error;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.EventKind;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.StepDepth;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.StepSize;
import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.SuspendPolicy;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.TypeTag;
import org.apache.harmony.jpda.tests.framework.jdwp.Location;
import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent.EventThread;
@@ -73,14 +77,15 @@
// Set to true to enable verbose logs
private static final boolean DEBUG_TESTS = false;
- private static final List<DexVm> UNSUPPORTED_ART_VERSIONS = ImmutableList.of(
+ private static final List<DexVm> UNSUPPORTED_ART_VERSIONS = ImmutableList.<DexVm>builder()
// Dalvik does not support command ReferenceType.Methods which is used to set breakpoint.
// TODO(shertz) use command ReferenceType.MethodsWithGeneric instead
- DexVm.ART_4_4_4,
+ .add(DexVm.ART_4_4_4)
// Older runtimes fail on buildbot
// TODO(shertz) re-enable once issue is solved
- DexVm.ART_5_1_1,
- DexVm.ART_6_0_1);
+ .add(DexVm.ART_5_1_1)
+ .add(DexVm.ART_6_0_1)
+ .build();
private static final Path JDWP_JAR = ToolHelper
.getJdwpTestsJarPath(ToolHelper.getMinApiLevelForDexVm(ToolHelper.getDexVm()));
@@ -200,7 +205,12 @@
}
protected final JUnit3Wrapper.Command breakpoint(String className, String methodName) {
- return new JUnit3Wrapper.Command.BreakpointCommand(className, methodName);
+ return breakpoint(className, methodName, null);
+ }
+
+ protected final JUnit3Wrapper.Command breakpoint(String className, String methodName,
+ String methodSignature) {
+ return new JUnit3Wrapper.Command.BreakpointCommand(className, methodName, methodSignature);
}
protected final JUnit3Wrapper.Command stepOver() {
@@ -244,12 +254,27 @@
return inspect(t -> Assert.assertTrue(t.getLocalNames().isEmpty()));
}
- protected final JUnit3Wrapper.Command checkLine(int line) {
- return inspect(t -> t.checkLine(line));
+ protected final JUnit3Wrapper.Command checkLine(String sourceFile, int line) {
+ return inspect(t -> {
+ Assert.assertEquals(sourceFile, t.getCurrentSourceFile());
+ Assert.assertEquals(line, t.getCurrentLineNumber());
+ });
}
protected final JUnit3Wrapper.Command checkMethod(String className, String methodName) {
- return inspect(t -> t.checkMethod(className, methodName));
+ return checkMethod(className, methodName, null);
+ }
+
+ protected final JUnit3Wrapper.Command checkMethod(String className, String methodName,
+ String methodSignature) {
+ return inspect(t -> {
+ Assert.assertEquals("Incorrect class name", className, t.getCurrentClassName());
+ Assert.assertEquals("Incorrect method name", methodName, t.getCurrentMethodName());
+ if (methodSignature != null) {
+ Assert.assertEquals("Incorrect method signature", methodSignature,
+ t.getCurrentMethodSignature());
+ }
+ });
}
protected final JUnit3Wrapper.Command inspect(Consumer<JUnit3Wrapper.DebuggeeState> inspector) {
@@ -477,26 +502,91 @@
Assert.assertEquals(expectedValue, localValue);
}
- public void checkLine(int line) {
- Location location = getLocation();
- int currentLine = getMirror()
- .getLineNumber(location.classID, location.methodID, location.index);
- Assert.assertEquals(line, currentLine);
+ public int getCurrentLineNumber() {
+ ReplyPacket reply = getMirror().getLineTable(location.classID, location.methodID);
+ if (reply.getErrorCode() != 0) {
+ return -1;
+ }
+
+ long startCodeIndex = reply.getNextValueAsLong();
+ long endCodeIndex = reply.getNextValueAsLong();
+ int lines = reply.getNextValueAsInt();
+ int line = -1;
+ long previousLineCodeIndex = -1;
+ for (int i = 0; i < lines; ++i) {
+ long currentLineCodeIndex = reply.getNextValueAsLong();
+ int currentLineNumber = reply.getNextValueAsInt();
+
+ // Code indices are in ascending order.
+ assert currentLineCodeIndex >= startCodeIndex;
+ assert currentLineCodeIndex <= endCodeIndex;
+ assert currentLineCodeIndex > previousLineCodeIndex;
+ previousLineCodeIndex = currentLineCodeIndex;
+
+ if (location.index >= currentLineCodeIndex) {
+ line = currentLineNumber;
+ } else {
+ break;
+ }
+ }
+
+ return line;
+ }
+
+ public String getCurrentSourceFile() {
+ CommandPacket sourceFileCommand = new CommandPacket(
+ JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+ JDWPCommands.ReferenceTypeCommandSet.SourceFileCommand);
+ sourceFileCommand.setNextValueAsReferenceTypeID(location.classID);
+ ReplyPacket replyPacket = getMirror().performCommand(sourceFileCommand);
+ if (replyPacket.getErrorCode() != 0) {
+ return null;
+ } else {
+ return replyPacket.getNextValueAsString();
+ }
}
public List<String> getLocalNames() {
return getVariablesAt(location).stream().map(v -> v.getName()).collect(Collectors.toList());
}
- public void checkMethod(String className, String methodName) {
- String currentClassSig = getMirror().getClassSignature(location.classID);
- assert currentClassSig.charAt(0) == 'L';
- String currentClassName = currentClassSig.substring(1, currentClassSig.length() - 1)
- .replace('/', '.');
- Assert.assertEquals("Incorrect class name", className, currentClassName);
+ public String getCurrentClassName() {
+ String classSignature = getCurrentClassSignature();
+ assert classSignature.charAt(0) == 'L';
+ // Remove leading 'L' and trailing ';'
+ classSignature = classSignature.substring(1, classSignature.length() - 1);
+ // Return fully qualified name
+ return classSignature.replace('/', '.');
+ }
- String currentMethodName = getMirror().getMethodName(location.classID, location.methodID);
- Assert.assertEquals("Incorrect method name", methodName, currentMethodName);
+ public String getCurrentClassSignature() {
+ return getMirror().getClassSignature(location.classID);
+ }
+
+ public String getCurrentMethodName() {
+ return getMirror().getMethodName(location.classID, location.methodID);
+ }
+
+ public String getCurrentMethodSignature() {
+ CommandPacket command = new CommandPacket(ReferenceTypeCommandSet.CommandSetID,
+ ReferenceTypeCommandSet.MethodsWithGenericCommand);
+ command.setNextValueAsReferenceTypeID(location.classID);
+
+ ReplyPacket reply = getMirror().performCommand(command);
+ assert reply.getErrorCode() == Error.NONE;
+ int methods = reply.getNextValueAsInt();
+
+ for (int i = 0; i < methods; ++i) {
+ long methodId = reply.getNextValueAsMethodID();
+ reply.getNextValueAsString(); // skip name
+ String methodSignature = reply.getNextValueAsString();
+ reply.getNextValueAsString(); // skip generic signature
+ reply.getNextValueAsInt(); // skip modifiers
+ if (methodId == location.methodID) {
+ return methodSignature;
+ }
+ }
+ throw new AssertionError("No method info for the current location");
}
}
@@ -564,7 +654,14 @@
}
private boolean installBreakpoint(BreakpointInfo breakpointInfo) {
- final long classId = getMirror().getClassID(getClassSignature(breakpointInfo.className));
+ String classSignature = getClassSignature(breakpointInfo.className);
+ byte typeTag = TypeTag.CLASS;
+ long classId = getMirror().getClassID(classSignature);
+ if (classId == -1) {
+ // Is it an interface ?
+ classId = getMirror().getInterfaceID(classSignature);
+ typeTag = TypeTag.INTERFACE;
+ }
if (classId == -1) {
// The class is not ready yet. Request a CLASS_PREPARE to delay the installation of the
// breakpoint.
@@ -575,14 +672,95 @@
new ClassPrepareHandler(breakpointInfo, classPrepareRequestId));
return false;
} else {
- int breakpointId = getMirror()
- .setBreakpointAtMethodBegin(classId, breakpointInfo.methodName);
+ // Find the method.
+ long breakpointMethodId = findMethod(classId, breakpointInfo.methodName,
+ breakpointInfo.methodSignature);
+ long index = getMethodFirstCodeIndex(classId, breakpointMethodId);
+ Assert.assertTrue("No code in method", index >= 0);
+ // Install the breakpoint.
+ ReplyPacket replyPacket = getMirror()
+ .setBreakpoint(new Location(typeTag, classId, breakpointMethodId, index),
+ SuspendPolicy.ALL);
+ checkReplyPacket(replyPacket, "Breakpoint");
+ int breakpointId = replyPacket.getNextValueAsInt();
// Nothing to do on breakpoint
events.put(Integer.valueOf(breakpointId), new DefaultEventHandler());
return true;
}
}
+ private long findMethod(long classId, String methodName, String methodSignature) {
+ class MethodInfo {
+
+ final long methodId;
+ final String methodName;
+ final String methodSignature;
+
+ MethodInfo(long methodId, String methodName, String methodSignature) {
+ this.methodId = methodId;
+ this.methodName = methodName;
+ this.methodSignature = methodSignature;
+ }
+ }
+
+ boolean withGenericSignature = true;
+ CommandPacket commandPacket = new CommandPacket(ReferenceTypeCommandSet.CommandSetID,
+ ReferenceTypeCommandSet.MethodsWithGenericCommand);
+ commandPacket.setNextValueAsReferenceTypeID(classId);
+ ReplyPacket replyPacket = getMirror().performCommand(commandPacket);
+ if (replyPacket.getErrorCode() != Error.NONE) {
+ // Retry with older command ReferenceType.Methods
+ withGenericSignature = false;
+ commandPacket.setCommand(ReferenceTypeCommandSet.MethodsCommand);
+ replyPacket = getMirror().performCommand(commandPacket);
+ assert replyPacket.getErrorCode() == Error.NONE;
+ }
+
+ int methodsCount = replyPacket.getNextValueAsInt();
+ List<MethodInfo> methodInfos = new ArrayList<>(methodsCount);
+ for (int i = 0; i < methodsCount; ++i) {
+ long currentMethodId = replyPacket.getNextValueAsMethodID();
+ String currentMethodName = replyPacket.getNextValueAsString();
+ String currentMethodSignature = replyPacket.getNextValueAsString();
+ if (withGenericSignature) {
+ replyPacket.getNextValueAsString(); // skip generic signature
+ }
+ replyPacket.getNextValueAsInt(); // skip modifiers
+ methodInfos
+ .add(new MethodInfo(currentMethodId, currentMethodName, currentMethodSignature));
+ }
+ Assert.assertTrue(replyPacket.isAllDataRead());
+
+ // Only keep methods with the expected name.
+ methodInfos = methodInfos.stream()
+ .filter(m -> m.methodName.equals(methodName)).collect(
+ Collectors.toList());
+ if (methodSignature != null) {
+ methodInfos = methodInfos.stream()
+ .filter(m -> methodSignature.equals(m.methodSignature)).collect(
+ Collectors.toList());
+ }
+ Assert.assertFalse("No method found", methodInfos.isEmpty());
+ // There must be only one matching method
+ Assert.assertEquals("More than 1 method found: please specify a signature", 1,
+ methodInfos.size());
+ return methodInfos.get(0).methodId;
+ }
+
+ private long getMethodFirstCodeIndex(long classId, long breakpointMethodId) {
+ ReplyPacket replyPacket = getMirror().getLineTable(classId, breakpointMethodId);
+ checkReplyPacket(replyPacket, "Failed to get method line table");
+ replyPacket.getNextValueAsLong(); // start
+ replyPacket.getNextValueAsLong(); // end
+ int linesCount = replyPacket.getNextValueAsInt();
+ if (linesCount == 0) {
+ return -1;
+ } else {
+ // Read only the 1st line because code indices are in ascending order
+ return replyPacket.getNextValueAsLong();
+ }
+ }
+
//
// Command processing
//
@@ -603,22 +781,24 @@
}
}
- // TODO(shertz) add method signature support (when multiple methods have the same name)
class BreakpointCommand implements Command {
private final String className;
private final String methodName;
+ private final String methodSignature;
- public BreakpointCommand(String className, String methodName) {
+ public BreakpointCommand(String className, String methodName,
+ String methodSignature) {
assert className != null;
assert methodName != null;
this.className = className;
this.methodName = methodName;
+ this.methodSignature = methodSignature;
}
@Override
public void perform(JUnit3Wrapper testBase) {
- testBase.installBreakpoint(new BreakpointInfo(className, methodName));
+ testBase.installBreakpoint(new BreakpointInfo(className, methodName, methodSignature));
}
@Override
@@ -740,10 +920,12 @@
private final String className;
private final String methodName;
+ private final String methodSignature;
- private BreakpointInfo(String className, String methodName) {
+ private BreakpointInfo(String className, String methodName, String methodSignature) {
this.className = className;
this.methodName = methodName;
+ this.methodSignature = methodSignature;
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/DefaultMethodTest.java b/src/test/java/com/android/tools/r8/debug/DefaultMethodTest.java
index ea116a7..e0eb5ea 100644
--- a/src/test/java/com/android/tools/r8/debug/DefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/DefaultMethodTest.java
@@ -11,6 +11,8 @@
public class DefaultMethodTest extends DebugTestBase {
+ private static final String SOURCE_FILE = "DebugDefaultMethod.java";
+
@Test
public void testDefaultMethod() throws Throwable {
String debuggeeClass = "DebugDefaultMethod";
@@ -21,7 +23,7 @@
commands.add(breakpoint(debuggeeClass, "testDefaultMethod"));
commands.add(run());
commands.add(checkMethod(debuggeeClass, "testDefaultMethod"));
- commands.add(checkLine(27));
+ commands.add(checkLine(SOURCE_FILE, 27));
if (!supportsDefaultMethod()) {
// We desugared default method. This means we're going to step through an extra (forward)
// method first.
@@ -50,7 +52,7 @@
commands.add(run());
commands.add(run() /* resume after 1st breakpoint */);
commands.add(checkMethod(debuggeeClass, "testDefaultMethod"));
- commands.add(checkLine(27));
+ commands.add(checkLine(SOURCE_FILE, 27));
commands.add(stepInto());
commands.add(checkMethod("DebugDefaultMethod$OverrideImpl", "doSomething"));
commands.add(checkLocal(parameterName));
@@ -61,5 +63,4 @@
runDebugTestJava8(debuggeeClass, commands);
}
-
}
diff --git a/src/test/java/com/android/tools/r8/debug/ExceptionTest.java b/src/test/java/com/android/tools/r8/debug/ExceptionTest.java
index 5f15f8f..3d4202b 100644
--- a/src/test/java/com/android/tools/r8/debug/ExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExceptionTest.java
@@ -10,6 +10,8 @@
*/
public class ExceptionTest extends DebugTestBase {
+ public static final String SOURCE_FILE = "Exceptions.java";
+
@Test
public void testStepOnCatch() throws Throwable {
int catchLine;
@@ -24,9 +26,9 @@
runDebugTest("Exceptions",
breakpoint("Exceptions", "catchException"),
run(),
- checkLine(9), // line of the method call throwing the exception
+ checkLine(SOURCE_FILE, 9), // line of the method call throwing the exception
stepOver(),
- checkLine(catchLine), // line of the catch declaration
+ checkLine(SOURCE_FILE, catchLine), // line of the catch declaration
run());
}
diff --git a/src/test/java/com/android/tools/r8/debug/LambdaTest.java b/src/test/java/com/android/tools/r8/debug/LambdaTest.java
index 467ae09..52d9c70 100644
--- a/src/test/java/com/android/tools/r8/debug/LambdaTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LambdaTest.java
@@ -8,6 +8,8 @@
public class LambdaTest extends DebugTestBase {
+ public static final String SOURCE_FILE = "DebugLambda.java";
+
@Test
public void testLambdaDebugging() throws Throwable {
String debuggeeClass = "DebugLambda";
@@ -17,9 +19,9 @@
breakpoint(debuggeeClass, initialMethodName),
run(),
checkMethod(debuggeeClass, initialMethodName),
- checkLine(12),
+ checkLine(SOURCE_FILE, 12),
stepInto(INTELLIJ_FILTER),
- checkLine(16),
+ checkLine(SOURCE_FILE, 16),
run());
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/LocalsTest.java b/src/test/java/com/android/tools/r8/debug/LocalsTest.java
index 0d72ab9..6132ace 100644
--- a/src/test/java/com/android/tools/r8/debug/LocalsTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LocalsTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
-import com.android.tools.r8.debug.DebugTestBase;
import org.apache.harmony.jpda.tests.framework.jdwp.Value;
import org.junit.Test;
@@ -12,6 +11,8 @@
*/
public class LocalsTest extends DebugTestBase {
+ public static final String SOURCE_FILE = "Locals.java";
+
@Test
public void testNoLocal() throws Throwable {
final String className = "Locals";
@@ -20,11 +21,11 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(8),
+ checkLine(SOURCE_FILE, 8),
checkNoLocal(),
stepOver(),
checkMethod(className, methodName),
- checkLine(9),
+ checkLine(SOURCE_FILE, 9),
checkNoLocal(),
run());
}
@@ -37,10 +38,10 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(12),
+ checkLine(SOURCE_FILE, 12),
checkNoLocal(),
stepOver(),
- checkLine(13),
+ checkLine(SOURCE_FILE, 13),
checkLocal("i", Value.createInt(Integer.MAX_VALUE)),
run());
}
@@ -57,14 +58,14 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(17),
+ checkLine(SOURCE_FILE, 17),
checkLocal("p", pValue),
stepOver(),
- checkLine(18),
+ checkLine(SOURCE_FILE, 18),
checkLocal("p", pValue),
checkLocal("c", cValue),
stepOver(),
- checkLine(19),
+ checkLine(SOURCE_FILE, 19),
checkLocal("p", pValue),
checkLocal("c", cValue),
checkLocal("v", vValue),
@@ -84,16 +85,16 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(17),
+ checkLine(SOURCE_FILE, 17),
checkLocal("p", pValue),
stepOver(),
- checkLine(18),
+ checkLine(SOURCE_FILE, 18),
checkLocal("p", pValue),
checkLocal("c", cValue),
setLocal("c", newValue),
checkLocal("c", newValue), // we should see the updated value
stepOver(),
- checkLine(19),
+ checkLine(SOURCE_FILE, 19),
checkLocal("p", pValue),
checkLocal("c", newValue),
checkLocal("v", vValue),
@@ -109,15 +110,15 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(23),
+ checkLine(SOURCE_FILE, 23),
checkNoLocal(),
stepOver(),
checkMethod(className, methodName),
- checkLine(24),
+ checkLine(SOURCE_FILE, 24),
checkLocal("i", Value.createInt(0)),
setLocal("i", newValueForI),
stepOver(),
- checkLine(25),
+ checkLine(SOURCE_FILE, 25),
checkLocal("i", newValueForI),
checkLocal("f", Value.createFloat(0)),
run());
@@ -133,15 +134,15 @@
breakpoint(className, methodName),
run(),
checkMethod(className, methodName),
- checkLine(29),
+ checkLine(SOURCE_FILE, 29),
checkNoLocal(),
stepOver(),
checkMethod(className, methodName),
- checkLine(30),
+ checkLine(SOURCE_FILE, 30),
checkLocal("i", oldValueForI),
setLocal("i", newValueForI),
stepOver(),
- checkLine(33),
+ checkLine(SOURCE_FILE, 33),
checkLocal("i", newValueForI),
run());
}
diff --git a/src/test/java/com/android/tools/r8/debug/MultipleReturnsTest.java b/src/test/java/com/android/tools/r8/debug/MultipleReturnsTest.java
index 0b7973e..1d708cf 100644
--- a/src/test/java/com/android/tools/r8/debug/MultipleReturnsTest.java
+++ b/src/test/java/com/android/tools/r8/debug/MultipleReturnsTest.java
@@ -10,16 +10,18 @@
*/
public class MultipleReturnsTest extends DebugTestBase {
+ public static final String SOURCE_FILE = "MultipleReturns.java";
+
@Test
public void testMultipleReturns() throws Throwable {
runDebugTest("MultipleReturns",
breakpoint("MultipleReturns", "multipleReturns"),
run(),
stepOver(),
- checkLine(16), // this should be the 1st return statement
+ checkLine(SOURCE_FILE, 16), // this should be the 1st return statement
run(),
stepOver(),
- checkLine(18), // this should be the 2nd return statement
+ checkLine(SOURCE_FILE, 18), // this should be the 2nd return statement
run());
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/SyntheticMethodTest.java b/src/test/java/com/android/tools/r8/debug/SyntheticMethodTest.java
index a5b7d4e..fa5917e 100644
--- a/src/test/java/com/android/tools/r8/debug/SyntheticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/SyntheticMethodTest.java
@@ -11,22 +11,6 @@
public class SyntheticMethodTest extends DebugTestBase {
- private void debugInnerAccessors(StepFilter stepFilter) throws Throwable {
- String debuggeeClass = "InnerAccessors";
- List<Command> commands = new ArrayList<>();
- commands.add(breakpoint("InnerAccessors$Inner", "callPrivateMethodInOuterClass"));
- commands.add(run());
- commands.add(checkLine(13));
- commands.add(stepInto(stepFilter)); // skip synthetic accessor
- if (stepFilter == NO_FILTER) {
- commands.add(stepInto(stepFilter));
- }
- commands.add(checkMethod(debuggeeClass, "privateMethod"));
- commands.add(checkLine(8));
- commands.add(run());
- runDebugTest(debuggeeClass, commands);
- }
-
@Test
public void testInnerAccessors_NoFilter() throws Throwable {
debugInnerAccessors(NO_FILTER);
@@ -37,4 +21,51 @@
debugInnerAccessors(INTELLIJ_FILTER);
}
+ @Test
+ public void testGenericBridges_NoFilter() throws Throwable {
+ debugGenericBridges(NO_FILTER);
+ }
+
+ @Test
+ public void testGenericBridges_IntelliJ() throws Throwable {
+ debugGenericBridges(INTELLIJ_FILTER);
+ }
+
+ private void debugInnerAccessors(StepFilter stepFilter) throws Throwable {
+ final String sourceFile = "InnerAccessors.java";
+ String debuggeeClass = "InnerAccessors";
+ List<Command> commands = new ArrayList<>();
+ commands.add(breakpoint("InnerAccessors$Inner", "callPrivateMethodInOuterClass"));
+ commands.add(run());
+ commands.add(checkLine(sourceFile, 13));
+ commands.add(stepInto(stepFilter)); // skip synthetic accessor
+ if (stepFilter == NO_FILTER) {
+ commands.add(stepInto(stepFilter));
+ }
+ commands.add(checkMethod(debuggeeClass, "privateMethod"));
+ commands.add(checkLine(sourceFile, 8));
+ commands.add(run());
+ runDebugTest(debuggeeClass, commands);
+ }
+
+ private void debugGenericBridges(StepFilter stepFilter) throws Throwable {
+ final String sourceFile = "Bridges.java";
+ String debuggeeClass = "Bridges";
+ List<Command> commands = new ArrayList<>();
+ commands.add(breakpoint(debuggeeClass, "testGenericBridge"));
+ commands.add(run());
+ commands.add(checkLine(sourceFile, 21));
+ commands.add(stepInto(stepFilter)); // skip synthetic accessor
+ String implementationClassName = "Bridges$StringImpl";
+ String methodName = "get";
+ if (stepFilter == NO_FILTER) {
+ commands.add(checkMethod(implementationClassName, methodName, "(Ljava/lang/Object;)V"));
+ commands.add(stepInto(stepFilter));
+ }
+ commands.add(checkMethod(implementationClassName, methodName, "(Ljava/lang/String;)V"));
+ commands.add(checkLine(sourceFile, 16));
+ commands.add(run());
+ runDebugTest(debuggeeClass, commands);
+ }
+
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index cab3291..ae0f650 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -4,41 +4,27 @@
package com.android.tools.r8.maindexlist;
-import static com.android.tools.r8.ToolHelper.EXAMPLES_DIR;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationResult;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.R8Command.Builder;
-import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.OffOrAuto;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
public class MainDexTracingTest {
@@ -155,11 +141,21 @@
.map(dexType -> dexType.descriptor.toString())
.collect(Collectors.toList());
Collections.sort(resultMainDexList);
- StringBuilder resultString = new StringBuilder();
- resultMainDexList.forEach(descriptor -> resultString.append(descriptor).append('\n'));
- String refList = new String(Files.readAllBytes(
- expectedMainDexList), StandardCharsets.UTF_8);
- Assert.assertEquals(refList, resultString.toString());
+ String[] refList = new String(Files.readAllBytes(
+ expectedMainDexList), StandardCharsets.UTF_8).split("\n");
+ for (int i = 0; i < refList.length; i++) {
+ String reference = refList[i];
+ String computed = resultMainDexList.get(i);
+ if (reference.contains("-$$Lambda$")) {
+ // For lambda classes we check that there is a lambda class for the right containing
+ // class. However, we do not check the hash for the generated lambda class. The hash
+ // changes for different compiler versions because different compiler versions generate
+ // different lambda implementation method names.
+ reference = reference.substring(0, reference.lastIndexOf('$'));
+ computed = computed.substring(0, computed.lastIndexOf('$'));
+ }
+ Assert.assertEquals(reference, computed);
+ }
} catch (ExecutionException e) {
throw e.getCause();
}
diff --git a/tools/create_jctf_tests.py b/tools/create_jctf_tests.py
index 0f1ca98..52907fc 100755
--- a/tools/create_jctf_tests.py
+++ b/tools/create_jctf_tests.py
@@ -71,7 +71,8 @@
raise IOError("Can't find package statement in java file: " + filepath)
-def generate_test(class_name, compiler_under_test, relative_package):
+def generate_test(class_name, compiler_under_test, compiler_under_test_enum,
+ relative_package):
filename = join(DESTINATION_DIR, compiler_under_test,
relative_package.replace('.', '/'), class_name + '.java')
utils.makedirs_if_needed(dirname(filename))
@@ -83,7 +84,7 @@
relativePackage = relative_package,
name = full_class_name,
testClassName = class_name,
- compilerUnderTestEnum = compiler_under_test.upper(),
+ compilerUnderTestEnum = compiler_under_test_enum,
classFile = full_class_name.replace('.', '/') + '.class',
nameWithoutPackagePrefix = '{}.{}'.format(relative_package, class_name))
@@ -120,8 +121,8 @@
assert idx >= 0
relative_package = package[idx + len(dot_java_dot):]
- for d in ['r8', 'd8']:
- generate_test(class_name, d, relative_package)
+ generate_test(class_name, 'd8', 'R8DEBUG_AFTER_D8', relative_package)
+ generate_test(class_name, 'r8', 'R8', relative_package)
if __name__ == '__main__':