Merge "Add a test for writing files with shared classes."
diff --git a/.gitignore b/.gitignore
index 088d2b9..0090fb9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,8 @@
third_party/jdwp-tests
third_party/kotlin.tar.gz
third_party/kotlin
+third_party/shadow
+third_party/shadow.tar.gz
third_party/photos/*
!third_party/photos/*.sha1
third_party/proguard/*
@@ -56,6 +58,7 @@
gradle-app.setting
gradlew
gradlew.bat
+gradle/*
#*#
*~
.#*
diff --git a/build.gradle b/build.gradle
index fdcc3bc..ac747c0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -184,44 +184,46 @@
def cloudDependencies = [
"tests" : [
- "2017-07-27/art.tar.gz",
- "2016-12-19/art.tar.gz"
+ "2017-07-27/art",
+ "2016-12-19/art"
],
"third_party": [
- "android_jar/lib-v14.tar.gz",
- "android_jar/lib-v19.tar.gz",
- "android_jar/lib-v21.tar.gz",
- "android_jar/lib-v24.tar.gz",
- "android_jar/lib-v25.tar.gz",
- "android_jar/lib-v26.tar.gz",
- "proguard/proguard5.2.1.tar.gz",
- "gradle/gradle.tar.gz",
- "jdwp-tests.tar.gz",
- "jasmin.tar.gz",
- "jctf.tar.gz",
- "kotlin.tar.gz",
- "android_cts_baseline.tar.gz",
- "shadow.tar.gz",
+ "android_jar/lib-v14",
+ "android_jar/lib-v19",
+ "android_jar/lib-v21",
+ "android_jar/lib-v24",
+ "android_jar/lib-v25",
+ "android_jar/lib-v26",
+ "proguard/proguard5.2.1",
+ "gradle/gradle",
+ "jdwp-tests",
+ "jasmin",
+ "jctf",
+ "kotlin",
+ "android_cts_baseline",
+ "shadow",
],
// All dex-vms have a fixed OS of Linux, as they are only supported on Linux, and will be run in a Docker
// container on other platforms where supported.
"tools" : [
- "linux/art.tar.gz",
- "linux/art-5.1.1.tar.gz",
- "linux/art-6.0.1.tar.gz",
- "linux/art-7.0.0.tar.gz",
- "linux/dalvik.tar.gz",
- "${osString}/dx.tar.gz",
+ "linux/art",
+ "linux/art-5.1.1",
+ "linux/art-6.0.1",
+ "linux/art-7.0.0",
+ "linux/dalvik",
+ "${osString}/dx",
]
]
cloudDependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
- def gzFile = "${entry.key}/${entryFile}"
+ def outputDir = "${entry.key}/${entryFile}"
+ def gzFile = "${outputDir}.tar.gz"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
+ outputs.dir outputDir
List<String> dlFromStorageArgs = ["-n", "-b", "r8-deps", "-u", "-s", "${sha1File}"]
if (OperatingSystem.current().isWindows()) {
executable "download_from_google_storage.bat"
@@ -236,33 +238,35 @@
def x20Dependencies = [
"third_party": [
- "gmail/gmail_android_170604.16.tar.gz",
- "gmscore/v4.tar.gz",
- "gmscore/v5.tar.gz",
- "gmscore/v6.tar.gz",
- "gmscore/v7.tar.gz",
- "gmscore/v8.tar.gz",
- "gmscore/gmscore_v9.tar.gz",
- "gmscore/gmscore_v10.tar.gz",
- "gmscore/latest.tar.gz",
- "photos/2017-06-06.tar.gz",
- "youtube/youtube.android_12.10.tar.gz",
- "youtube/youtube.android_12.17.tar.gz",
- "youtube/youtube.android_12.22.tar.gz",
- "proguardsettings.tar.gz",
- "proguard/proguard_internal_159423826.tar.gz",
- "framework.tar.gz",
- "goyt.tar.gz",
+ "gmail/gmail_android_170604.16",
+ "gmscore/v4",
+ "gmscore/v5",
+ "gmscore/v6",
+ "gmscore/v7",
+ "gmscore/v8",
+ "gmscore/gmscore_v9",
+ "gmscore/gmscore_v10",
+ "gmscore/latest",
+ "photos/2017-06-06",
+ "youtube/youtube.android_12.10",
+ "youtube/youtube.android_12.17",
+ "youtube/youtube.android_12.22",
+ "proguardsettings",
+ "proguard/proguard_internal_159423826",
+ "framework",
+ "goyt",
],
]
x20Dependencies.each { entry ->
entry.value.each { entryFile ->
task "download_deps_${entry.key}/${entryFile}"(type: Exec) {
- def gzFile = "${entry.key}/${entryFile}"
+ def outputDir = "${entry.key}/${entryFile}"
+ def gzFile = "${outputDir}.tar.gz"
def sha1File = "${gzFile}.sha1"
inputs.file sha1File
outputs.file gzFile
+ outputs.dir outputDir
executable "bash"
args "-c", "tools/download_from_x20.py ${sha1File}"
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index 14e5288..a5a63e3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -86,7 +86,7 @@
// If this is the end of the block clear out the pending state.
pendingLocals = null;
pendingLocalChanges = false;
- } else if (pc != emittedPc && !instruction.isNop()) {
+ } else if (pc != emittedPc && !instruction.isDebugLocalRead()) {
// For non-exit / pc-advancing instructions emit any pending changes once possible.
emitLocalChanges(pc);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index 5089ca5..aebb9ed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -126,14 +126,14 @@
}
@Override
- public void removeOrReplaceByNop() {
+ public void removeOrReplaceByDebugLocalRead() {
if (current == null) {
throw new IllegalStateException();
}
if (current.getDebugValues().isEmpty()) {
remove();
} else {
- replaceCurrentInstruction(new Nop());
+ replaceCurrentInstruction(new DebugLocalRead());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Nop.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
similarity index 76%
rename from src/main/java/com/android/tools/r8/ir/code/Nop.java
rename to src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
index dc378de..f0eb4a5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Nop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -10,25 +10,25 @@
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.utils.InternalOptions;
-public class Nop extends Instruction {
+public class DebugLocalRead extends Instruction {
- public Nop() {
+ public DebugLocalRead() {
super(null);
}
@Override
- public boolean isNop() {
+ public boolean isDebugLocalRead() {
return true;
}
@Override
- public Nop asNop() {
+ public DebugLocalRead asDebugLocalRead() {
return this;
}
@Override
public void buildDex(DexBuilder builder) {
- builder.addNop(this);
+ throw new Unreachable("Unexpected attempt to emit debug-local read.");
}
@Override
@@ -58,6 +58,8 @@
@Override
public boolean canBeDeadCode(IRCode code, InternalOptions options) {
- return getDebugValues().isEmpty();
+ // Reads are never dead code.
+ // They should also have a non-empty set of debug values (see RegAlloc::computeDebugInfo)
+ return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionsIterator.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionsIterator.java
index 1390620..1bedf26 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionsIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionsIterator.java
@@ -53,7 +53,7 @@
}
@Override
- public void removeOrReplaceByNop() {
- instructionIterator.removeOrReplaceByNop();
+ public void removeOrReplaceByDebugLocalRead() {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 801c684..15291a5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -849,11 +849,11 @@
return null;
}
- public boolean isNop() {
+ public boolean isDebugLocalRead() {
return false;
}
- public Nop asNop() {
+ public DebugLocalRead asDebugLocalRead() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionIterator.java
index 56d81a2..2f2b3f1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionIterator.java
@@ -33,8 +33,8 @@
void add(Instruction instruction);
/**
- * Safe removal function that will insert a Nop to take over the debug values if any are
- * associated with the current instruction.
+ * Safe removal function that will insert a DebugLocalRead to take over the debug values if any
+ * are associated with the current instruction.
*/
- void removeOrReplaceByNop();
+ void removeOrReplaceByDebugLocalRead();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index d8ea70b..92491c3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -60,10 +60,10 @@
}
/**
- * Safe removal function that will insert a Nop to take over the debug values if any are
- * associated with the current instruction.
+ * Safe removal function that will insert a DebugLocalRead to take over the debug values if any
+ * are associated with the current instruction.
*/
- void removeOrReplaceByNop();
+ void removeOrReplaceByDebugLocalRead();
/**
* Remove the current instruction (aka the {@link Instruction} returned by the previous call to
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 3bdeefa..0d96df7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -353,8 +353,7 @@
}
private static boolean isNopInstruction(com.android.tools.r8.ir.code.Instruction instruction) {
- return instruction.isNop()
- || instruction.isDebugLocalsChange()
+ return instruction.isDebugLocalsChange()
|| (instruction.isConstNumber() && !instruction.outValue().needsRegister());
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index f2dfce4..fc516e4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -35,6 +35,7 @@
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.ConstType;
+import com.android.tools.r8.ir.code.DebugLocalRead;
import com.android.tools.r8.ir.code.DebugLocalUninitialized;
import com.android.tools.r8.ir.code.DebugLocalWrite;
import com.android.tools.r8.ir.code.DebugPosition;
@@ -59,7 +60,6 @@
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewArrayFilledData;
import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.Nop;
import com.android.tools.r8.ir.code.Not;
import com.android.tools.r8.ir.code.NumberConversion;
import com.android.tools.r8.ir.code.NumericType;
@@ -608,7 +608,7 @@
// 1. The block is empty (eg, instructions from block entry until now materialized to nothing).
// 2. The block is non-empty (and the last instruction does not define the local to start).
if (currentBlock.getInstructions().isEmpty()) {
- addInstruction(new Nop());
+ addInstruction(new DebugLocalRead());
}
Instruction instruction = currentBlock.getInstructions().getLast();
assert instruction.outValue() != value;
@@ -630,7 +630,7 @@
// 2. The block has an instruction not defining the local being ended.
// 3. The block has an instruction defining the local being ended.
if (currentBlock.getInstructions().isEmpty()) {
- addInstruction(new Nop());
+ addInstruction(new DebugLocalRead());
}
Instruction instruction = currentBlock.getInstructions().getLast();
if (instruction.outValue() != value) {
@@ -645,7 +645,7 @@
if (instruction.isDebugLocalWrite()) {
DebugLocalWrite write = instruction.asDebugLocalWrite();
currentBlock.replaceCurrentDefinitions(value, write.src());
- currentBlock.listIterator(write).removeOrReplaceByNop();
+ currentBlock.listIterator(write).removeOrReplaceByDebugLocalRead();
} else {
instruction.outValue().clearLocalInfo();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
index 828ff10..f11af49 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarState.java
@@ -176,7 +176,7 @@
// without conflating locals that are shared among different types. This issue arises because a
// debugging range can be larger than the definite-assignment scope of a local (eg, a local
// introduced in an unscoped switch case). To ensure that the SSA graph is valid we must introduce
- // the local before inserting any DebugLocalReads (we do so in the method prelude, but that can
+ // the local before inserting any DebugLocalRead (we do so in the method prelude, but that can
// potentially lead to phi functions merging locals of different move-types. Thus we allocate
// registers from the three distinct spaces.
private final int localsSize;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 7a8a4c3..ca307f4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1088,7 +1088,7 @@
user -> user.isCheckCast()
&& user.asCheckCast().getType().isSubtypeOf(checkCast.getType(), appInfo))) {
checkCast.outValue().replaceUsers(checkCast.inValues().get(0));
- it.removeOrReplaceByNop();
+ it.removeOrReplaceByDebugLocalRead();
}
}
}
@@ -1369,7 +1369,8 @@
InstructionListIterator it = block.listIterator();
while (it.hasNext()) {
Instruction instruction = it.next();
- if (!isPrimitiveOrStringNewArrayWithPositiveSize(instruction)) {
+ if (instruction.getLocalInfo() != null
+ || !isPrimitiveOrStringNewArrayWithPositiveSize(instruction)) {
continue;
}
NewArrayEmpty newArray = instruction.asNewArrayEmpty();
@@ -1507,7 +1508,7 @@
write.outValue().replaceUsers(phi);
// Safely remove the write.
// TODO(zerny): Once phis become instructions, move debug values there instead of a nop.
- iterator.removeOrReplaceByNop();
+ iterator.removeOrReplaceByDebugLocalRead();
return;
}
}
@@ -1671,6 +1672,10 @@
|| instruction.isUnop()
|| instruction.isInstanceOf()
|| instruction.isCheckCast()) {
+ if (instruction.getLocalInfo() != null || instruction.hasInValueWithLocalInfo()) {
+ // If the instruction has input or output values then it is not safe to share it.
+ continue;
+ }
List<Value> candidates = instructionToValue.get(equivalence.wrap(instruction));
boolean eliminated = false;
if (candidates.size() > 0) {
@@ -1679,12 +1684,12 @@
shareCatchHandlers(instruction, candidate.definition)) {
instruction.outValue().replaceUsers(candidate);
eliminated = true;
- iterator.removeOrReplaceByNop();
+ iterator.removeOrReplaceByDebugLocalRead();
break; // Don't try any more candidates.
}
}
}
- if (!eliminated && !instruction.hasInValueWithLocalInfo()) {
+ if (!eliminated) {
instructionToValue.put(equivalence.wrap(instruction), instruction.outValue());
}
}
@@ -1928,13 +1933,13 @@
DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod();
if (matchesMethodOfThrowable(invokedMethod, throwableMethods.addSuppressed)) {
// Remove Throwable::addSuppressed(Throwable) call.
- iterator.removeOrReplaceByNop();
+ iterator.removeOrReplaceByDebugLocalRead();
} else if (matchesMethodOfThrowable(invokedMethod, throwableMethods.getSuppressed)) {
Value destValue = current.outValue();
if (destValue == null) {
// If the result of the call was not used we don't create
// an empty array and just remove the call.
- iterator.removeOrReplaceByNop();
+ iterator.removeOrReplaceByDebugLocalRead();
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index ebf69b5..2790c03 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -120,7 +120,7 @@
// All users will be removed for this instruction. Eagerly clear them so further inspection
// of this instruction during dead code elimination will terminate here.
outValue.clearUsers();
- iterator.removeOrReplaceByNop();
+ iterator.removeOrReplaceByDebugLocalRead();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index a8b3972..7facea6 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -324,6 +324,12 @@
int spillCount = 0;
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
+ if (instruction.isDebugLocalRead()) {
+ // Remove debug local reads now that local liveness is computed.
+ assert !instruction.getDebugValues().isEmpty();
+ instruction.clearDebugValues();
+ instructionIterator.remove();
+ }
int index = instruction.getNumber();
if (index == -1) {
spillCount++;
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 1f9101c..cc01eab 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -52,6 +52,7 @@
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.Method;
import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent;
import org.apache.harmony.jpda.tests.framework.jdwp.ParsedEvent.EventThread;
import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
@@ -91,9 +92,7 @@
// Set to true to enable verbose logs
private static final boolean DEBUG_TESTS = false;
- // Dalvik does not support command ReferenceType.Methods which is used to set breakpoint.
- // TODO(shertz) use command ReferenceType.MethodsWithGeneric instead
- private static final List<DexVm> UNSUPPORTED_ART_VERSIONS = ImmutableList.of(DexVm.ART_4_4_4);
+ private static final List<DexVm> UNSUPPORTED_ART_VERSIONS = ImmutableList.of();
private static final Path JDWP_JAR = ToolHelper
.getJdwpTestsJarPath(ToolHelper.getMinApiLevelForDexVm(ToolHelper.getDexVm()));
@@ -579,16 +578,19 @@
if (DEBUG_TESTS && debuggeeState.getLocation() != null) {
// Dump location
String classSig = getMirror().getClassSignature(debuggeeState.getLocation().classID);
- String methodName = getMirror()
- .getMethodName(debuggeeState.getLocation().classID,
+ String methodName = VmMirrorUtils
+ .getMethodName(getMirror(), debuggeeState.getLocation().classID,
debuggeeState.getLocation().methodID);
- String methodSig = getMirror()
- .getMethodSignature(debuggeeState.getLocation().classID,
+ String methodSig = VmMirrorUtils
+ .getMethodSignature(getMirror(), debuggeeState.getLocation().classID,
debuggeeState.getLocation().methodID);
- System.out.println(String
- .format("Suspended in %s#%s%s@0x%x (line=%d)", classSig, methodName, methodSig,
- Long.valueOf(debuggeeState.getLocation().index),
- Integer.valueOf(debuggeeState.getLineNumber())));
+ String msg = String
+ .format("Suspended in %s#%s%s@0x%x", classSig, methodName, methodSig,
+ Long.valueOf(debuggeeState.getLocation().index));
+ if (debuggeeState.getLocation().index >= 0) {
+ msg += " (line " + debuggeeState.getLineNumber() + ")";
+ }
+ System.out.println(msg);
}
// Handle event.
@@ -611,7 +613,7 @@
artCommandBuilder.appendArtOption("-Xcompiler-option");
artCommandBuilder.appendArtOption("--debuggable");
}
- if (DEBUG_TESTS) {
+ if (DEBUG_TESTS && ToolHelper.getDexVm().isNewerThan(DexVm.ART_4_4_4)) {
artCommandBuilder.appendArtOption("-verbose:jdwp");
}
setProperty("jpda.settings.debuggeeJavaPath", artCommandBuilder.build());
@@ -1450,7 +1452,7 @@
@Override
public boolean skipLocation(VmMirror mirror, Location location) {
- // TODO(shertz) we also need to skip class loaders to act like IntelliJ.
+ // TODO(b/67225390) we also need to skip class loaders to act like IntelliJ.
// Skip synthetic methods.
if (isLambdaMethod(mirror, location)) {
// Lambda methods are synthetic but we do want to stop there.
@@ -1478,15 +1480,10 @@
private static boolean isSyntheticMethod(VmMirror mirror, Location location) {
// We must gather the modifiers of the method. This is only possible using
// ReferenceType.Methods command which gather information about all methods in a class.
- ReplyPacket reply = mirror.getMethods(location.classID);
- int methodsCount = reply.getNextValueAsInt();
- for (int i = 0; i < methodsCount; ++i) {
- long methodId = reply.getNextValueAsMethodID();
- reply.getNextValueAsString(); // skip method name
- reply.getNextValueAsString(); // skip method signature
- int modifiers = reply.getNextValueAsInt();
- if (methodId == location.methodID &&
- ((modifiers & SYNTHETIC_FLAG) != 0)) {
+ Method[] methods = mirror.getMethods(location.classID);
+ for (Method method : methods) {
+ if (method.getMethodID() == location.methodID &&
+ ((method.getModBits() & SYNTHETIC_FLAG) != 0)) {
return true;
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestExamples.java b/src/test/java/com/android/tools/r8/debug/DebugTestExamples.java
index 39091fb..91fed63 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestExamples.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestExamples.java
@@ -12,12 +12,15 @@
*/
public class DebugTestExamples extends DebugTestBase {
+ public static final String SOURCE_FILE = "Arithmetic.java";
+ public static final String DEBUGGEE_CLASS = "Arithmetic";
+
/**
* Simple test that runs the debuggee until it exits.
*/
@Test
public void testRun() throws Throwable {
- runDebugTest("Arithmetic", Collections.singletonList(run()));
+ runDebugTest(DEBUGGEE_CLASS, Collections.singletonList(run()));
}
/**
@@ -25,9 +28,10 @@
*/
@Test
public void testBreakpoint_Hit() throws Throwable {
- runDebugTest("Arithmetic",
- breakpoint("Arithmetic", "bitwiseInts"),
+ runDebugTest(DEBUGGEE_CLASS,
+ breakpoint(DEBUGGEE_CLASS, "bitwiseInts"),
run(),
+ checkLine(SOURCE_FILE, 12),
run());
}
@@ -36,9 +40,10 @@
*/
@Test
public void testLocalsOnBreakpoint() throws Throwable {
- runDebugTest("Arithmetic",
- breakpoint("Arithmetic", "bitwiseInts"),
+ runDebugTest(DEBUGGEE_CLASS,
+ breakpoint(DEBUGGEE_CLASS, "bitwiseInts"),
run(),
+ checkLine(SOURCE_FILE, 12),
checkLocal("x", Value.createInt(12345)),
checkLocal("y", Value.createInt(54321)),
run());
@@ -49,9 +54,10 @@
*/
@Test
public void testLocalsOnBreakpointThenStep() throws Throwable {
- runDebugTest("Arithmetic",
- breakpoint("Arithmetic", "bitwiseInts"),
+ runDebugTest(DEBUGGEE_CLASS,
+ breakpoint(DEBUGGEE_CLASS, "bitwiseInts"),
run(),
+ checkLine(SOURCE_FILE, 12),
checkLocal("x", Value.createInt(12345)),
checkLocal("y", Value.createInt(54321)),
stepOver(),
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index a7dcb60..03f011f 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -4,9 +4,15 @@
package com.android.tools.r8.debug;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
+import com.android.tools.r8.debug.DebugTestBase.StepFilter.IntelliJStepFilter;
import java.util.ArrayList;
import java.util.List;
+import org.junit.Assume;
import org.junit.Test;
public class InterfaceMethodTest extends DebugTestBase {
@@ -15,6 +21,10 @@
@Test
public void testDefaultMethod() throws Throwable {
+ // TODO(b/67225390) Dalvik steps into class loader first.
+ Assume.assumeTrue("Dalvik suspends in class loader",
+ ToolHelper.getDexVm().isNewerThan(DexVm.ART_4_4_4));
+
String debuggeeClass = "DebugInterfaceMethod";
String parameterName = "msg";
String localVariableName = "name";
@@ -30,6 +40,7 @@
commands.add(stepInto());
}
commands.add(stepInto());
+ commands.add(checkLine(SOURCE_FILE, 9));
// TODO(shertz) we should see the local variable this even when desugaring.
if (supportsDefaultMethod()) {
commands.add(checkLocal("this"));
diff --git a/src/test/java/com/android/tools/r8/debug/VmMirrorUtils.java b/src/test/java/com/android/tools/r8/debug/VmMirrorUtils.java
new file mode 100644
index 0000000..a3983da
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/VmMirrorUtils.java
@@ -0,0 +1,86 @@
+// 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.
+
+package com.android.tools.r8.debug;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+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.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants.Error;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.VmMirror;
+
+/**
+ * Utils for JDWP mirror.
+ */
+public abstract class VmMirrorUtils {
+
+ private VmMirrorUtils() {
+ }
+
+ public static void checkReply(ReplyPacket replyPacket) {
+ checkReply(replyPacket, Error.NONE);
+ }
+
+ public static void checkReply(ReplyPacket replyPacket, int expectedErrorCode) {
+ if (replyPacket.getErrorCode() != expectedErrorCode) {
+ throw new AssertionError(
+ "Expected error code " + JDWPConstants.Error.getName(expectedErrorCode) + " ("
+ + expectedErrorCode + ") but received " + JDWPConstants.Error
+ .getName(expectedErrorCode) + " (" + expectedErrorCode + ")");
+ }
+
+ }
+
+ public static String getMethodName(VmMirror mirror, long classID, long methodID) {
+ CommandPacket packet = new CommandPacket(
+ JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+ ReferenceTypeCommandSet.MethodsWithGenericCommand);
+ packet.setNextValueAsReferenceTypeID(classID);
+ ReplyPacket reply = mirror.performCommand(packet);
+ checkReply(reply);
+ int methodsCount = reply.getNextValueAsInt();
+ String result = null;
+ for (int i = 0; i < methodsCount; i++) {
+ long id = reply.getNextValueAsMethodID(); // skip method ID
+ String methodName = reply.getNextValueAsString();
+ reply.getNextValueAsString(); // skip signature
+ reply.getNextValueAsString(); // skip generic signature
+ reply.getNextValueAsInt(); // skip modifiers
+ if (id == methodID) {
+ result = methodName;
+ }
+ }
+ assert reply.isAllDataRead();
+ return result;
+ }
+
+ public static String getMethodSignature(VmMirror mirror, long classID, long methodID) {
+ CommandPacket command = new CommandPacket(
+ ReferenceTypeCommandSet.CommandSetID,
+ ReferenceTypeCommandSet.MethodsWithGenericCommand);
+ command.setNextValueAsReferenceTypeID(classID);
+ ReplyPacket reply = mirror.performCommand(command);
+ checkReply(reply);
+
+ int methods = reply.getNextValueAsInt();
+ for (int i = 0; i < methods; i++) {
+ long mID = reply.getNextValueAsMethodID();
+ reply.getNextValueAsString(); // skip method name
+ String methodSign = reply.getNextValueAsString();
+ reply.getNextValueAsString(); // skip generic signature
+ reply.getNextValueAsInt(); // skip modifiers
+ if (mID == methodID) {
+ String value = methodSign.replaceAll("/", ".");
+ int lastRoundBracketIndex = value.lastIndexOf(")");
+ return value.substring(0, lastRoundBracketIndex + 1);
+ }
+ }
+
+ assert reply.isAllDataRead();
+ return null;
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 8ab2de5..c8ea3bb 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -74,7 +74,7 @@
}
@Override
- public void removeOrReplaceByNop() {
+ public void removeOrReplaceByDebugLocalRead() {
remove();
}
diff --git a/third_party/jdwp-tests.tar.gz.sha1 b/third_party/jdwp-tests.tar.gz.sha1
index 20b141e..dd998eb 100644
--- a/third_party/jdwp-tests.tar.gz.sha1
+++ b/third_party/jdwp-tests.tar.gz.sha1
@@ -1 +1 @@
-dd8dade9e939ae693b0b824d84268d09fa9f36cd
\ No newline at end of file
+c1f8da93dfe1b811904ee19a670fb5ed1a35766f
\ No newline at end of file
diff --git a/tools/test.py b/tools/test.py
index 9774207..7818915 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -84,9 +84,6 @@
def Main():
(options, args) = ParseOptions()
- if len(args) > 1:
- print("test.py takes at most one argument, the pattern for tests to run")
- return -1
gradle_args = []
# Set all necessary Gradle properties and options first.
@@ -131,10 +128,10 @@
# Add Gradle tasks
gradle_args.append('cleanTest')
gradle_args.append('test')
- if len(args) > 0:
- # Test filtering. Must always follow the 'test' task.
+ # Test filtering. Must always follow the 'test' task.
+ for testFilter in args:
gradle_args.append('--tests')
- gradle_args.append(args[0])
+ gradle_args.append(testFilter)
if options.with_code_coverage:
# Create Jacoco report after tests.
gradle_args.append('jacocoTestReport')