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()); }