Reland "Reland "Add regression test for missing locals in desugared lambdas.""
This reverts commit cc106188deeedf2dab3963e7e7b50e097611cc34.
Reason for revert: Pinned JDK9 should resolve the bot issue.
Bug: 123390221
Change-Id: Ia80174ab6a9638a6d4f6aa2e705bbee306480b77
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 fb61f45..1c0287e 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 com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.TestDescriptionWatcher;
@@ -50,6 +51,7 @@
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.ObjectReferenceCommandSet;
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;
@@ -153,6 +155,12 @@
}
protected final void runDebugTest(
+ DebugTestConfig config, Class<?> debuggeeClass, JUnit3Wrapper.Command... commands)
+ throws Throwable {
+ runInternal(config, debuggeeClass.getTypeName(), Arrays.asList(commands));
+ }
+
+ protected final void runDebugTest(
DebugTestConfig config, String debuggeeClass, JUnit3Wrapper.Command... commands)
throws Throwable {
runInternal(config, debuggeeClass, Arrays.asList(commands));
@@ -324,6 +332,10 @@
return new JUnit3Wrapper.Command.RunCommand();
}
+ protected final JUnit3Wrapper.Command breakpoint(MethodReference method) {
+ return breakpoint(method.getHolderClass().getTypeName(), method.getMethodName());
+ }
+
protected final JUnit3Wrapper.Command breakpoint(String className, String methodName) {
return breakpoint(className, methodName, null);
}
@@ -477,6 +489,10 @@
});
}
+ protected final JUnit3Wrapper.Command checkLine(int line) {
+ return inspect(t -> t.checkLine(null, line));
+ }
+
protected final JUnit3Wrapper.Command checkLine(String sourceFile, int line) {
return inspect(t -> t.checkLine(sourceFile, line));
}
@@ -532,6 +548,16 @@
});
}
+ protected final JUnit3Wrapper.Command checkFieldOnThis(
+ String fieldName, String fieldSignature, Value expectedValue) {
+ return inspect(
+ t -> {
+ Value value = t.getFieldOnThis(fieldName, fieldSignature);
+ Assert.assertEquals(
+ "Incorrect value for field 'this." + fieldName + "'", expectedValue, value);
+ });
+ }
+
protected final JUnit3Wrapper.Command inspect(Consumer<JUnit3Wrapper.DebuggeeState> inspector) {
return t -> inspector.accept(t.debuggeeState);
}
@@ -1298,6 +1324,7 @@
@Override
public void checkLine(String sourceFile, int line) {
+ sourceFile = sourceFile != null ? sourceFile : getSourceFile();
if (!Objects.equals(sourceFile, getSourceFile()) || line != getLineNumber()) {
String locationString = convertCurrentLocationToString();
Assert.fail(
@@ -1501,7 +1528,15 @@
// The class is available, lookup and read the field.
long fieldId = findField(getMirror(), classId, fieldName, fieldSignature);
- return getField(getMirror(), classId, fieldId);
+ return internalStaticField(getMirror(), classId, fieldId);
+ }
+
+ public Value getFieldOnThis(String fieldName, String fieldSignature) {
+ long thisObjectId = getMirror().getThisObject(getThreadId(), getFrameId());
+ long classId = getMirror().getReferenceType(thisObjectId);
+ // TODO(zerny): Search supers too. This will only get the field if directly on the class.
+ long fieldId = findField(getMirror(), classId, fieldName, fieldSignature);
+ return internalInstanceField(getMirror(), thisObjectId, fieldId);
}
private long findField(VmMirror mirror, long classId, String fieldName,
@@ -1547,10 +1582,10 @@
return matchingFieldIds.getLong(0);
}
- private Value getField(VmMirror mirror, long classId, long fieldId) {
-
- CommandPacket commandPacket = new CommandPacket(ReferenceTypeCommandSet.CommandSetID,
- ReferenceTypeCommandSet.GetValuesCommand);
+ private static Value internalStaticField(VmMirror mirror, long classId, long fieldId) {
+ CommandPacket commandPacket =
+ new CommandPacket(
+ ReferenceTypeCommandSet.CommandSetID, ReferenceTypeCommandSet.GetValuesCommand);
commandPacket.setNextValueAsReferenceTypeID(classId);
commandPacket.setNextValueAsInt(1);
commandPacket.setNextValueAsFieldID(fieldId);
@@ -1565,6 +1600,23 @@
}
}
+ private static Value internalInstanceField(VmMirror mirror, long objectId, long fieldId) {
+ CommandPacket commandPacket =
+ new CommandPacket(
+ ObjectReferenceCommandSet.CommandSetID, ObjectReferenceCommandSet.GetValuesCommand);
+ commandPacket.setNextValueAsObjectID(objectId);
+ commandPacket.setNextValueAsInt(1);
+ commandPacket.setNextValueAsFieldID(fieldId);
+ ReplyPacket replyPacket = mirror.performCommand(commandPacket);
+ assert replyPacket.getErrorCode() == Error.NONE;
+
+ int fieldsCount = replyPacket.getNextValueAsInt();
+ assert fieldsCount == 1;
+ Value result = replyPacket.getNextValueAsValue();
+ Assert.assertTrue(replyPacket.isAllDataRead());
+ return result;
+ }
+
public static Optional<Variable> getVariableAt(VmMirror mirror, Location location,
String localName) {
return getVariablesAt(mirror, location).stream()
diff --git a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTest.java b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTest.java
new file mode 100644
index 0000000..9991b57
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTest.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, 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;
+
+public class LambdaOuterContextTest {
+
+ public interface Converter {
+ String convert(int value);
+ }
+
+ public int outer;
+
+ public LambdaOuterContextTest(int outer) {
+ this.outer = outer;
+ }
+
+ public void foo(Converter converter) {
+ System.out.println(converter.convert(outer));
+ }
+
+ public void bar(int arg) {
+ foo(value -> {
+ // Ensure lambda uses parts of the outer context, otherwise javac will optimize it out.
+ return Integer.toString(outer + value + arg);
+ });
+ }
+
+ public static void main(String[] args) {
+ new LambdaOuterContextTest(args.length + 42).bar(args.length);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
new file mode 100644
index 0000000..8af2a6e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/LambdaOuterContextTestRunner.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2019, 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 static com.android.tools.r8.references.Reference.methodFromMethod;
+
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.JvmTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.debug.LambdaOuterContextTest.Converter;
+import com.android.tools.r8.utils.StringUtils;
+import org.apache.harmony.jpda.tests.framework.jdwp.Value;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class LambdaOuterContextTestRunner extends DebugTestBase {
+
+ public static final Class<?> CLASS = LambdaOuterContextTest.class;
+ public static final String EXPECTED = StringUtils.lines("84");
+
+ @Test
+ public void testJvm() throws Throwable {
+ JvmTestBuilder jvmTestBuilder = testForJvm().addTestClasspath();
+ jvmTestBuilder.run(CLASS).assertSuccessWithOutput(EXPECTED);
+ runDebugger(jvmTestBuilder.debugConfig());
+ }
+
+ @Test
+ @Ignore("b/123068053")
+ public void testD8() throws Throwable {
+ D8TestCompileResult compileResult =
+ testForD8().addProgramClassesAndInnerClasses(CLASS).compile();
+ compileResult.run(CLASS).assertSuccessWithOutput(EXPECTED);
+ runDebugger(compileResult.debugConfig());
+ }
+
+ @Test
+ public void testR8Cf() throws Throwable {
+ R8TestCompileResult compileResult =
+ testForR8(Backend.CF)
+ .addProgramClassesAndInnerClasses(CLASS)
+ .debug()
+ .noMinification()
+ .noTreeShaking()
+ .compile();
+ compileResult.run(CLASS).assertSuccessWithOutput(EXPECTED);
+ runDebugger(compileResult.debugConfig());
+ }
+
+ private void runDebugger(DebugTestConfig config) throws Throwable {
+ runDebugTest(
+ config,
+ CLASS,
+ breakpoint(methodFromMethod(CLASS.getMethod("foo", Converter.class))),
+ run(),
+ checkLine(19),
+ checkLocals("this", "converter"),
+ checkFieldOnThis("outer", null, Value.createInt(42)),
+ stepInto(INTELLIJ_FILTER),
+ checkLine(25),
+ checkLocals("this", "value", "arg"),
+ checkNoLocal("outer"),
+ checkFieldOnThis("outer", null, Value.createInt(42)),
+ 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 1b413ba..f9e6c34 100644
--- a/src/test/java/com/android/tools/r8/debug/LambdaTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LambdaTest.java
@@ -13,7 +13,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-// TODO(shertz) test local variables
@RunWith(Parameterized.class)
public class LambdaTest extends DebugTestBase {
@@ -47,8 +46,11 @@
run(),
checkMethod(debuggeeClass, initialMethodName),
checkLine(SOURCE_FILE, 12),
+ checkLocals("i"),
+ checkNoLocal("j"),
stepInto(INTELLIJ_FILTER),
checkLine(SOURCE_FILE, 16),
+ checkLocals("i", "j"),
run());
}
@@ -63,8 +65,10 @@
run(),
checkMethod(debuggeeClass, initialMethodName),
checkLine(SOURCE_FILE, 32),
+ checkLocals("i", "a", "b"),
stepInto(INTELLIJ_FILTER),
checkLine(SOURCE_FILE, 37),
+ checkLocals("a", "b"),
run());
}