Update asm to version 9.5
Change-Id: I7e9f4adc2bef84ebfb7deab303799cb9f7c3ec1a
diff --git a/build.gradle b/build.gradle
index fe2980a..85e3fc6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,7 +29,7 @@
ext {
androidSupportVersion = '25.4.0'
- asmVersion = '9.4' // When updating update tools/asmifier.py, build.src and Toolhelper as well.
+ asmVersion = '9.5' // When updating update tools/asmifier.py, build.src and Toolhelper as well.
javassistVersion = '3.29.2-GA'
espressoVersion = '3.0.0'
fastutilVersion = '7.2.0'
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 88e29ab..bfe46c2 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -9,7 +9,7 @@
}
ext {
- asmVersion = '9.4'
+ asmVersion = '9.5'
}
dependencies {
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java
index 1fd5ce7..f69e532 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVersion.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -44,6 +44,8 @@
public static final CfVersion V19_PREVIEW = new CfVersion(Opcodes.V19 | Opcodes.V_PREVIEW);
public static final CfVersion V20 = new CfVersion(Opcodes.V20);
public static final CfVersion V20_PREVIEW = new CfVersion(Opcodes.V20 | Opcodes.V_PREVIEW);
+ public static final CfVersion V21 = new CfVersion(Opcodes.V21);
+ public static final CfVersion V21_PREVIEW = new CfVersion(Opcodes.V21 | Opcodes.V_PREVIEW);
private final int version;
@@ -67,7 +69,8 @@
CfVersion.V17,
CfVersion.V18,
CfVersion.V19,
- CfVersion.V20
+ CfVersion.V20,
+ CfVersion.V21
};
// Private constructor in case we want to canonicalize versions.
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index dbed84f..4df769b 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.CfVersion;
-import com.android.tools.r8.cf.code.CfFrame;
import com.android.tools.r8.cf.code.CfFrameVerifier;
import com.android.tools.r8.cf.code.CfFrameVerifier.StackMapStatus;
import com.android.tools.r8.cf.code.CfFrameVerifierEventConsumer;
@@ -417,24 +416,6 @@
return preamble;
}
- private static class PrunePreambleMethodVisitor extends MethodVisitor {
-
- private boolean inPreamble = true;
-
- public PrunePreambleMethodVisitor(MethodVisitor methodVisitor) {
- super(InternalOptions.ASM_VERSION, methodVisitor);
- }
-
- @Override
- public void visitLineNumber(int line, Label start) {
- if (line == 0 && inPreamble) {
- return;
- }
- inPreamble = false;
- super.visitLineNumber(line, start);
- }
- }
-
@Override
public void writeCf(
ProgramMethod method,
@@ -460,20 +441,20 @@
|| (appView.enableWholeProgramOptimizations()
&& classFileVersion.isEqualTo(CfVersion.V1_6)
&& !options.shouldKeepStackMapTable());
- PrunePreambleMethodVisitor prunePreambleVisitor = new PrunePreambleMethodVisitor(visitor);
+ Position preamblePosition = getPreamblePosition();
+ boolean discardPreamble = preamblePosition != null && preamblePosition.isSyntheticPosition();
for (CfInstruction instruction : instructions) {
- if (discardFrames && instruction instanceof CfFrame) {
+ if (discardFrames && instruction.isFrame()) {
+ continue;
+ }
+ if (discardPreamble
+ && instruction.isPosition()
+ && instruction.asPosition().getPosition().equals(preamblePosition)) {
+ discardPreamble = false;
continue;
}
instruction.write(
- appView,
- method,
- dexItemFactory,
- graphLens,
- initClassLens,
- namingLens,
- rewriter,
- prunePreambleVisitor);
+ appView, method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
}
visitor.visitEnd();
visitor.visitMaxs(maxStack, maxLocals);
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 cf7a34f..588ce91 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
@@ -789,6 +789,9 @@
while (it.hasNext()) {
Instruction instruction = it.next();
Position position = instruction.getPosition();
+ if (instruction.isArgument()) {
+ continue;
+ }
if (instruction.isMoveException()) {
assert current == null;
current = position;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index cd3c1c5..d256489 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -153,7 +153,7 @@
}
}
- public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V20;
+ public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V21;
public static final int SUPPORTED_DEX_VERSION =
AndroidApiLevel.LATEST.getDexVersion().getIntValue();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 8479714..7ac3869 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -138,8 +138,8 @@
public static final String R8_TEST_BUCKET = "r8-test-results";
- public static final String ASM_JAR = BUILD_DIR + "deps/asm-9.4.jar";
- public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-9.4.jar";
+ public static final String ASM_JAR = BUILD_DIR + "deps/asm-9.5.jar";
+ public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-9.5.jar";
public static final Path API_SAMPLE_JAR = Paths.get("tests", "r8_api_usage_sample.jar");
diff --git a/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java b/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
index a281690..90fd31b 100644
--- a/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
+++ b/src/test/java/com/android/tools/r8/cf/CompanionClassPreamblePositionTest.java
@@ -16,9 +16,11 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import java.nio.file.Path;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -70,14 +72,21 @@
}
private void checkZeroLineIsPresent(CodeInspector inspector) throws Exception {
- // ASM skips zero lines so use javap to check the presence of a zero line.
+ // Until version 9.5, ASM skips zero lines so use javap to check the presence of a zero line.
ClassSubject itf = inspector.clazz(I.class);
assertThat(itf.javap(true), containsString("line 0: 0"));
+ // Having updated to ASM 9.5 we can also check using code inspector.
+ Assert.assertTrue(itf.uniqueMethod().getLineNumberTable().getLines().contains(0));
}
private void checkZeroLineNotPresent(CodeInspector inspector) throws Exception {
+ // Until version 9.5, ASM skips zero lines so use javap to check the absence of a zero line.
ClassSubject companion = inspector.companionClassFor(I.class);
assertThat(companion.javap(true), not(containsString("line 0: 0")));
+ // Having updated to ASM 9.5 we can also check using code inspector.
+ MethodSubject method = companion.uniqueMethod();
+ Assert.assertTrue(method.hasLineNumberTable());
+ Assert.assertFalse(method.getLineNumberTable().getLines().contains(0));
}
private byte[] getTransformedI(boolean includeZero) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/cf/LeadingZeroPositionTest.java b/src/test/java/com/android/tools/r8/cf/LeadingZeroPositionTest.java
new file mode 100644
index 0000000..28dc97e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/LeadingZeroPositionTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2023, 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.cf;
+
+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.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class LeadingZeroPositionTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDefaultRuntimes()
+ .withApiLevel(AndroidApiLevel.B)
+ .enableApiLevelsForCf()
+ .build();
+ }
+
+ public LeadingZeroPositionTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testZeroInInput() throws Exception {
+ Assume.assumeTrue(parameters.isCfRuntime());
+ testForJvm(parameters)
+ .addProgramClassFileData(getTransformedClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkZeroLineIsPresent);
+ }
+
+ @Test
+ public void testZeroAfterD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getTransformedClass())
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(this::checkZeroLineIsPresent);
+ }
+
+ private void checkZeroLineIsPresent(CodeInspector inspector) throws Exception {
+ MethodSubject method = inspector.clazz(TestClass.class).mainMethod();
+ assertTrue(method.getLineNumberTable().getLines().contains(0));
+ }
+
+ private byte[] getTransformedClass() throws Exception {
+ return transformer(TestClass.class)
+ .setPredictiveLineNumbering(MethodPredicate.onName("main"), 0)
+ .transform();
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.nanoTime(); // line 0 - input line, so we expect to preserve it to the output.
+ System.nanoTime(); // line 100
+ System.nanoTime(); // line 200
+ System.nanoTime(); // line 300
+ System.out.println("Hello, world"); // line 400
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/MultipleZeroPositionsTest.java b/src/test/java/com/android/tools/r8/cf/MultipleZeroPositionsTest.java
new file mode 100644
index 0000000..d32a594
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/MultipleZeroPositionsTest.java
@@ -0,0 +1,122 @@
+// Copyright (c) 2023, 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.cf;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.transformers.ClassFileTransformer.LineTranslation;
+import com.android.tools.r8.transformers.MethodTransformer.MethodContext;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MultipleZeroPositionsTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDefaultCfRuntime()
+ .withApiLevel(AndroidApiLevel.B)
+ .enableApiLevelsForCf()
+ .build();
+ }
+
+ public MultipleZeroPositionsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testZeroInInput() throws Exception {
+ testForJvm(parameters)
+ .addProgramClassFileData(getTransformedClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkZeroLineCount);
+ }
+
+ @Test
+ public void testZeroAfterD8() throws Exception {
+ Path out =
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getTransformedClass())
+ .setMinApi(parameters)
+ .compile()
+ .writeToZip();
+ testForJvm(parameters)
+ .addProgramFiles(out)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkZeroLineCount);
+ }
+
+ private void checkZeroLineCount(CodeInspector inspector) throws Exception {
+ int expected = 3;
+ // Until version 9.5, ASM skips zero lines so use javap to check the presence of a zero line.
+ ClassSubject clazz = inspector.clazz(TestClass.class);
+ String javap = clazz.javap(true);
+ int actual = countOccurrences(javap, "line 0: ");
+ assertEquals(
+ "Expected " + expected + " 'line 0' entries, got " + actual + "\n" + javap,
+ expected,
+ actual);
+ }
+
+ private int countOccurrences(String string, String substring) {
+ int i = 0;
+ int found = 0;
+ while (true) {
+ i = string.indexOf(substring, i);
+ if (i == -1) {
+ return found;
+ }
+ ++found;
+ ++i;
+ }
+ }
+
+ private byte[] getTransformedClass() throws Exception {
+ return transformer(TestClass.class)
+ .setPredictiveLineNumbering(
+ new LineTranslation() {
+ Int2IntMap map = new Int2IntOpenHashMap();
+
+ @Override
+ public int translate(MethodContext context, int inputLine) {
+ if (context.getReference().getMethodName().equals("main")) {
+ return map.computeIfAbsent(
+ inputLine, ignore -> map.size() % 2 == 0 ? 1 + map.size() : 0);
+ }
+ return inputLine;
+ }
+ })
+ .transform();
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.nanoTime(); // line
+ System.nanoTime(); // 0
+ System.nanoTime(); // line
+ System.nanoTime(); // 0
+ System.out.println("Hello, world");
+ ; // line
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java b/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
index acbe0e5..0436b0d 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/AsmZeroLineEntryRegressionTest.java
@@ -62,8 +62,8 @@
getClassWithZeroLineEntry(), Reference.classFromClass(TestClass.class)))
.run(parameters.getRuntime(), TestClass.class)
.assertFailureWithErrorThatThrows(RuntimeException.class)
- // If this becomes zero ASM has been updated to not assign line zero a special meaning.
- .inspectOriginalStackTrace(st -> checkLineNumber(st, 1));
+ // From version 9.5 ASM was updated to not assign line zero a special meaning.
+ .inspectOriginalStackTrace(st -> checkLineNumber(st, 0));
}
private void checkLineNumber(StackTrace st, int lineNumber) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java
index 3831e44..1e47370 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoLineInfoTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
import com.android.tools.r8.utils.BooleanUtils;
import java.io.IOException;
import java.util.Collections;
@@ -48,7 +49,7 @@
private byte[] getTestClassTransformed() throws IOException {
return transformer(TestClass.class)
.setSourceFile(INPUT_SOURCE_FILE)
- .setPredictiveLineNumbering()
+ .setPredictiveLineNumbering(MethodPredicate.all(), -1 /* start with no line */)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 63573d2..e010aa2 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -1282,7 +1282,7 @@
}
public ClassFileTransformer setPredictiveLineNumbering(MethodPredicate predicate) {
- return setPredictiveLineNumbering(predicate, 0);
+ return setPredictiveLineNumbering(predicate, 100);
}
public interface LineTranslation {
@@ -1306,7 +1306,8 @@
int nextLine = lines.getOrDefault(method, startingLineNumber);
// Increment the actual line content by 100 so that each one is clearly distinct
// from a PC value for any of the methods.
- lines.put(method, nextLine + 100);
+ int nextNextLine = nextLine == -1 ? 100 : nextLine + 100;
+ lines.put(method, nextNextLine);
return nextLine;
}
return line;
diff --git a/tools/asmifier.py b/tools/asmifier.py
index 82b90af..504f2bf 100755
--- a/tools/asmifier.py
+++ b/tools/asmifier.py
@@ -10,7 +10,7 @@
import sys
import utils
-ASM_VERSION = '9.4'
+ASM_VERSION = '9.5'
ASM_JAR = 'asm-' + ASM_VERSION + '.jar'
ASM_UTIL_JAR = 'asm-util-' + ASM_VERSION + '.jar'