Merge commit 'f300db13a3e7d158ad40a5d675cc73ee285f75ac' into dev-release
diff --git a/build.gradle b/build.gradle
index f775822..bde2f60 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1091,6 +1091,7 @@
task rawBuildLibraryDesugarConversions(type: Zip, dependsOn: downloadDeps) {
from sourceSets.libraryDesugarConversions.output
include "java/**/*.class"
+ include "desugar/sun/nio/fs/DesugarAndroid*.class"
baseName 'library_desugar_conversions_raw'
destinationDir file('build/tmp/desugaredlibrary')
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
index 37c4087..029ec75 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
@@ -168,7 +168,7 @@
itemBuilder.setClassPattern(classNamePattern);
}
if (methodName != null) {
- itemBuilder.setMembersPattern(
+ itemBuilder.setMemberPattern(
KeepMethodPattern.builder().setNamePattern(methodName).build());
}
KeepTarget target = KeepTarget.builder().setItem(itemBuilder.build()).build();
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
index 0e96364..8307265 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
+import com.android.tools.r8.keepanno.ast.KeepMemberPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern.KeepMethodNameExactPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepPreconditions;
@@ -70,21 +70,21 @@
if (!item.getExtendsPattern().isAny()) {
throw new Unimplemented();
}
- writeMembers(item.getMembersPattern(), targetVisitor);
+ writeMember(item.getMemberPattern(), targetVisitor);
targetVisitor.visitEnd();
});
arrayVisitor.visitEnd();
}
- private void writeMembers(KeepMembersPattern membersPattern, AnnotationVisitor targetVisitor) {
- if (membersPattern.isNone()) {
+ private void writeMember(KeepMemberPattern memberPattern, AnnotationVisitor targetVisitor) {
+ if (memberPattern.isNone()) {
// Default is "no methods".
return;
}
- if (membersPattern.isAll()) {
+ if (memberPattern.isAll()) {
throw new Unimplemented();
}
- KeepMethodPattern method = membersPattern.asMethod();
+ KeepMethodPattern method = memberPattern.asMethod();
KeepMethodNameExactPattern exactMethodName = method.getNamePattern().asExact();
if (exactMethodName != null) {
targetVisitor.visit(Target.methodName, exactMethodName.getName());
@@ -95,7 +95,14 @@
throw new Unimplemented();
}
if (!method.getReturnTypePattern().isAny()) {
- throw new Unimplemented();
+ if (exactMethodName != null
+ && (exactMethodName.getName().equals("<init>")
+ || exactMethodName.getName().equals("<clinit>"))
+ && method.getReturnTypePattern().isVoid()) {
+ // constructors have implicit void return.
+ } else {
+ throw new Unimplemented();
+ }
}
if (!method.getParametersPattern().isAny()) {
throw new Unimplemented();
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
index 5271837..89be76b 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
@@ -25,12 +25,13 @@
* CONDITION ::= ITEM_PATTERN
*
* CONSEQUENCES ::= TARGET+
- * TARGET ::= any | OPTIONS ITEM_PATTERN // TODO(b/248408342): What options are on target 'any'?
+ * TARGET ::= OPTIONS ITEM_PATTERN
* OPTIONS ::= keep-all | OPTION+
* OPTION ::= shrinking | optimizing | obfuscating | access-modifying
*
- * ITEM_PATTERN ::=
- * class QUALIFIED_CLASS_NAME_PATTERN extends EXTENDS_PATTERN { MEMBERS_PATTERN }
+ * ITEM_PATTERN
+ * ::= any
+ * | class QUALIFIED_CLASS_NAME_PATTERN extends EXTENDS_PATTERN { MEMBER_PATTERN }
*
* TYPE_PATTERN ::= any
* PACKAGE_PATTERN ::= any | exact package-name
@@ -38,7 +39,7 @@
* UNQUALIFIED_CLASS_NAME_PATTERN ::= any | exact simple-class-name
* EXTENDS_PATTERN ::= any | QUALIFIED_CLASS_NAME_PATTERN
*
- * MEMBERS_PATTERN ::= none | all | METHOD_PATTERN
+ * MEMBER_PATTERN ::= none | all | METHOD_PATTERN
*
* METHOD_PATTERN
* ::= METHOD_ACCESS_PATTERN
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
index 68c5c17..50d3921 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepItemPattern.java
@@ -31,14 +31,14 @@
private KeepQualifiedClassNamePattern classNamePattern;
private KeepExtendsPattern extendsPattern = KeepExtendsPattern.any();
- private KeepMembersPattern membersPattern = KeepMembersPattern.none();
+ private KeepMemberPattern memberPattern = KeepMemberPattern.none();
private Builder() {}
public Builder any() {
classNamePattern = KeepQualifiedClassNamePattern.any();
extendsPattern = KeepExtendsPattern.any();
- membersPattern = KeepMembersPattern.all();
+ memberPattern = KeepMemberPattern.all();
return this;
}
@@ -52,8 +52,8 @@
return this;
}
- public Builder setMembersPattern(KeepMembersPattern membersPattern) {
- this.membersPattern = membersPattern;
+ public Builder setMemberPattern(KeepMemberPattern memberPattern) {
+ this.memberPattern = memberPattern;
return this;
}
@@ -61,29 +61,29 @@
if (classNamePattern == null) {
throw new KeepEdgeException("Class pattern must define a class name pattern.");
}
- return new KeepItemPattern(classNamePattern, extendsPattern, membersPattern);
+ return new KeepItemPattern(classNamePattern, extendsPattern, memberPattern);
}
}
private final KeepQualifiedClassNamePattern qualifiedClassPattern;
private final KeepExtendsPattern extendsPattern;
- private final KeepMembersPattern membersPattern;
+ private final KeepMemberPattern memberPattern;
// TODO: class annotations
private KeepItemPattern(
KeepQualifiedClassNamePattern qualifiedClassPattern,
KeepExtendsPattern extendsPattern,
- KeepMembersPattern membersPattern) {
+ KeepMemberPattern memberPattern) {
assert qualifiedClassPattern != null;
assert extendsPattern != null;
- assert membersPattern != null;
+ assert memberPattern != null;
this.qualifiedClassPattern = qualifiedClassPattern;
this.extendsPattern = extendsPattern;
- this.membersPattern = membersPattern;
+ this.memberPattern = memberPattern;
}
public boolean isAny() {
- return qualifiedClassPattern.isAny() && extendsPattern.isAny() && membersPattern.isAll();
+ return qualifiedClassPattern.isAny() && extendsPattern.isAny() && memberPattern.isAll();
}
public KeepQualifiedClassNamePattern getClassNamePattern() {
@@ -94,8 +94,8 @@
return extendsPattern;
}
- public KeepMembersPattern getMembersPattern() {
- return membersPattern;
+ public KeepMemberPattern getMemberPattern() {
+ return memberPattern;
}
@Override
@@ -109,12 +109,12 @@
KeepItemPattern that = (KeepItemPattern) obj;
return qualifiedClassPattern.equals(that.qualifiedClassPattern)
&& extendsPattern.equals(that.extendsPattern)
- && membersPattern.equals(that.membersPattern);
+ && memberPattern.equals(that.memberPattern);
}
@Override
public int hashCode() {
- return Objects.hash(qualifiedClassPattern, extendsPattern, membersPattern);
+ return Objects.hash(qualifiedClassPattern, extendsPattern, memberPattern);
}
@Override
@@ -124,8 +124,8 @@
+ qualifiedClassPattern
+ ", extendsPattern="
+ extendsPattern
- + ", membersPattern="
- + membersPattern
+ + ", memberPattern="
+ + memberPattern
+ '}';
}
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
similarity index 84%
rename from src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java
rename to src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
index 64e1b25..25a57ab 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMembersPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
@@ -3,18 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
+public abstract class KeepMemberPattern {
-public abstract class KeepMembersPattern {
-
- public static KeepMembersPattern none() {
+ public static KeepMemberPattern none() {
return None.getInstance();
}
- public static KeepMembersPattern all() {
+ public static KeepMemberPattern all() {
return All.getInstance();
}
- private static class All extends KeepMembersPattern {
+ private static class All extends KeepMemberPattern {
private static final All INSTANCE = new All();
@@ -43,7 +42,7 @@
}
}
- private static class None extends KeepMembersPattern {
+ private static class None extends KeepMemberPattern {
private static final None INSTANCE = new None();
@@ -72,7 +71,7 @@
}
}
- KeepMembersPattern() {}
+ KeepMemberPattern() {}
public boolean isAll() {
return false;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
index bec8102..e00fedd 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
@@ -3,9 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
+import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern.KeepMethodNameExactPattern;
import java.util.Objects;
-public final class KeepMethodPattern extends KeepMembersPattern {
+public final class KeepMethodPattern extends KeepMemberPattern {
public static Builder builder() {
return new Builder();
@@ -48,6 +49,15 @@
if (namePattern == null) {
throw new KeepEdgeException("Method pattern must declar a name pattern");
}
+ KeepMethodReturnTypePattern returnTypePattern = this.returnTypePattern;
+ KeepMethodNameExactPattern exactName = namePattern.asExact();
+ if (exactName != null
+ && (exactName.getName().equals("<init>") || exactName.getName().equals("<clinit>"))) {
+ if (!this.returnTypePattern.isAny() && !this.returnTypePattern.isVoid()) {
+ throw new KeepEdgeException("Method constructor pattern must match 'void' type.");
+ }
+ returnTypePattern = KeepMethodReturnTypePattern.voidType();
+ }
return new KeepMethodPattern(
accessPattern, namePattern, returnTypePattern, parametersPattern);
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
index 111022b..6b7a212 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTarget.java
@@ -7,10 +7,6 @@
public class KeepTarget {
- public static KeepTarget any() {
- return KeepTarget.builder().setItem(KeepItemPattern.any()).build();
- }
-
public static class Builder {
private KeepItemPattern item;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
index 3ab882f..7c8c032 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMembersPattern;
+import com.android.tools.r8.keepanno.ast.KeepMemberPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodAccessPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
import com.android.tools.r8.keepanno.ast.KeepMethodParametersPattern;
@@ -102,16 +102,16 @@
if (!clazzPattern.getExtendsPattern().isAny()) {
throw new Unimplemented();
}
- KeepMembersPattern members = clazzPattern.getMembersPattern();
- if (members.isNone()) {
+ KeepMemberPattern member = clazzPattern.getMemberPattern();
+ if (member.isNone()) {
return builder;
}
- if (members.isAll()) {
+ if (member.isAll()) {
return builder.append(" { *; }");
}
- if (members.isMethod()) {
+ if (member.isMethod()) {
builder.append(" {");
- printMethod(builder.append(' '), members.asMethod());
+ printMethod(builder.append(' '), member.asMethod());
return builder.append(" }");
}
throw new Unimplemented();
@@ -132,7 +132,7 @@
private static StringBuilder printParameters(
StringBuilder builder, KeepMethodParametersPattern parametersPattern) {
if (parametersPattern.isAny()) {
- return builder.append("(***)");
+ return builder.append("(...)");
}
return builder
.append('(')
@@ -160,7 +160,7 @@
private static StringBuilder printType(StringBuilder builder, KeepTypePattern typePattern) {
if (typePattern.isAny()) {
- return builder.append("*");
+ return builder.append("***");
}
throw new Unimplemented();
}
@@ -232,7 +232,7 @@
public boolean isMemberOnlyConsequent() {
KeepItemPattern item = target.getItem();
- return !item.isAny() && !item.getMembersPattern().isNone();
+ return !item.isAny() && !item.getMemberPattern().isNone();
}
public KeepQualifiedClassNamePattern getHolderPattern() {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java b/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
index 58601a6..c86857d 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessor.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.keepanno.ast.KeepConsequences;
import com.android.tools.r8.keepanno.ast.KeepEdge;
import com.android.tools.r8.keepanno.ast.KeepEdge.Builder;
+import com.android.tools.r8.keepanno.ast.KeepEdgeException;
import com.android.tools.r8.keepanno.ast.KeepItemPattern;
import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
@@ -125,17 +126,31 @@
edgeBuilder.setConsequences(consequencesBuilder.build());
}
+ private String getTypeNameForClassConstantElement(DeclaredType type) {
+ // The processor API does not expose the descriptor or typename, so we need to depend on the
+ // sun.tools internals to extract it. If not, this code will not work for inner classes as
+ // we cannot recover the $ separator.
+ try {
+ Object tsym = type.getClass().getField("tsym").get(type);
+ Object flatname = tsym.getClass().getField("flatname").get(tsym);
+ return flatname.toString();
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new KeepEdgeException("Unable to obtain the class type name for: " + type);
+ }
+ }
+
private void processTarget(KeepTarget.Builder builder, AnnotationMirror mirror) {
KeepItemPattern.Builder itemBuilder = KeepItemPattern.builder();
AnnotationValue classConstantValue = getAnnotationValue(mirror, Target.classConstant);
if (classConstantValue != null) {
DeclaredType type = AnnotationClassValueVisitor.getType(classConstantValue);
- itemBuilder.setClassPattern(KeepQualifiedClassNamePattern.exact(type.toString()));
+ String typeName = getTypeNameForClassConstantElement(type);
+ itemBuilder.setClassPattern(KeepQualifiedClassNamePattern.exact(typeName));
}
AnnotationValue methodNameValue = getAnnotationValue(mirror, Target.methodName);
if (methodNameValue != null) {
String methodName = AnnotationStringValueVisitor.getString(methodNameValue);
- itemBuilder.setMembersPattern(
+ itemBuilder.setMemberPattern(
KeepMethodPattern.builder()
.setNamePattern(KeepMethodNamePattern.exact(methodName))
.build());
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidDefaultFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidDefaultFileSystemProvider.java
new file mode 100644
index 0000000..8de3f76
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidDefaultFileSystemProvider.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2022, 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 desugar.sun.nio.fs;
+
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.spi.FileSystemProvider;
+
+public class DesugarAndroidDefaultFileSystemProvider {
+ private static final FileSystemProvider INSTANCE = DesugarAndroidFileSystemProvider.create();
+
+ private DesugarAndroidDefaultFileSystemProvider() {}
+
+ /** Returns the platform's default file system provider. */
+ public static FileSystemProvider instance() {
+ return INSTANCE;
+ }
+
+ /** Returns the platform's default file system. */
+ public static FileSystem theFileSystem() {
+ return INSTANCE.getFileSystem(URI.create("file:///"));
+ }
+}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidFileSystemProvider.java
new file mode 100644
index 0000000..027d74f
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarAndroidFileSystemProvider.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, 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 desugar.sun.nio.fs;
+
+import java.adapter.AndroidVersionTest;
+import java.io.IOException;
+import java.nio.channels.DesugarChannels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Set;
+
+/** Linux implementation of {@link FileSystemProvider} for desugar support. */
+public class DesugarAndroidFileSystemProvider
+ extends desugar.sun.nio.fs.DesugarLinuxFileSystemProvider {
+
+ public static DesugarAndroidFileSystemProvider create() {
+ return new DesugarAndroidFileSystemProvider(System.getProperty("user.dir"), "/");
+ }
+
+ DesugarAndroidFileSystemProvider(String userDir, String rootDir) {
+ super(userDir, rootDir);
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(
+ Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ if (path.toFile().isDirectory()) {
+ throw new UnsupportedOperationException(
+ "The desugar library does not support creating a file channel on a directory: " + path);
+ }
+ // A FileChannel is a SeekableByteChannel.
+ return newFileChannel(path, options, attrs);
+ }
+
+ @Override
+ public FileChannel newFileChannel(
+ Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ if (AndroidVersionTest.is26OrAbove) {
+ throw new RuntimeException("Above Api 26, the platform FileSystemProvider should be used.");
+ }
+ return DesugarChannels.openEmulatedFileChannel(path, options, attrs);
+ }
+}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
deleted file mode 100644
index cf36b80..0000000
--- a/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2022, 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 desugar.sun.nio.fs;
-
-import java.nio.file.spi.FileSystemProvider;
-
-public class DesugarDefaultFileSystemProvider {
-
- public static FileSystemProvider instance() {
- return null;
- }
-}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarLinuxFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarLinuxFileSystemProvider.java
new file mode 100644
index 0000000..566bf12
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarLinuxFileSystemProvider.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2022, 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 desugar.sun.nio.fs;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Map;
+import java.util.Set;
+
+public class DesugarLinuxFileSystemProvider extends FileSystemProvider {
+
+ DesugarLinuxFileSystemProvider(String userDir, String rootDir) {
+ super();
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public FileSystem newFileSystem(URI uri, Map<String, ?> map) throws IOException {
+ return null;
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ return null;
+ }
+
+ @Override
+ public Path getPath(URI uri) {
+ return null;
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(
+ Path path, Set<? extends OpenOption> set, FileAttribute<?>... fileAttributes)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public DirectoryStream<Path> newDirectoryStream(Path path, Filter<? super Path> filter)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public void createDirectory(Path path, FileAttribute<?>... fileAttributes) throws IOException {}
+
+ @Override
+ public void delete(Path path) throws IOException {}
+
+ @Override
+ public void copy(Path path, Path path1, CopyOption... copyOptions) throws IOException {}
+
+ @Override
+ public void move(Path path, Path path1, CopyOption... copyOptions) throws IOException {}
+
+ @Override
+ public boolean isSameFile(Path path, Path path1) throws IOException {
+ return false;
+ }
+
+ @Override
+ public boolean isHidden(Path path) throws IOException {
+ return false;
+ }
+
+ @Override
+ public FileStore getFileStore(Path path) throws IOException {
+ return null;
+ }
+
+ @Override
+ public void checkAccess(Path path, AccessMode... accessModes) throws IOException {}
+
+ @Override
+ public <V extends FileAttributeView> V getFileAttributeView(
+ Path path, Class<V> aClass, LinkOption... linkOptions) {
+ return null;
+ }
+
+ @Override
+ public <A extends BasicFileAttributes> A readAttributes(
+ Path path, Class<A> aClass, LinkOption... linkOptions) throws IOException {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> readAttributes(Path path, String s, LinkOption... linkOptions)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(Path path, String s, Object o, LinkOption... linkOptions)
+ throws IOException {}
+}
diff --git a/src/library_desugar/java/java/adapter/AndroidVersionTest.java b/src/library_desugar/java/java/adapter/AndroidVersionTest.java
new file mode 100644
index 0000000..065761e
--- /dev/null
+++ b/src/library_desugar/java/java/adapter/AndroidVersionTest.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2022, 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 java.adapter;
+
+public class AndroidVersionTest {
+
+ public static final boolean is24OrAbove = setUp("java.util.StringJoiner");
+ public static final boolean is26OrAbove = setUp("java.nio.file.FileSystems");
+ public static final boolean isHeadfull = setUp("android.os.Build");
+
+ /**
+ * Answers true if the class is present, implying the SDK is at least at the level where the class
+ * was introduced.
+ */
+ private static boolean setUp(String className) {
+ try {
+ Class.forName(className);
+ return true;
+ } catch (ClassNotFoundException ignored) {
+ }
+ return false;
+ }
+}
diff --git a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
index e34e571..eea074f 100644
--- a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
+++ b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
@@ -6,7 +6,7 @@
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
-import desugar.sun.nio.fs.DesugarDefaultFileSystemProvider;
+import desugar.sun.nio.fs.DesugarAndroidDefaultFileSystemProvider;
import j$.nio.file.FileSystems;
import java.net.URI;
import java.nio.file.FileSystem;
@@ -23,27 +23,18 @@
INSTANCE.getFileSystem(URI.create("file:///"));
private static FileSystemProvider getFileSystemProvider() {
- // Note: this fails on non Android devices.
- try {
+ if (AndroidVersionTest.is26OrAbove) {
// On API 26 and above, FileSystems is present.
- Class.forName("java.nio.file.FileSystems");
j$.nio.file.FileSystem fileSystem = FileSystems.getDefault();
j$.nio.file.spi.FileSystemProvider provider = fileSystem.provider();
return j$.nio.file.spi.FileSystemProvider.wrap_convert(provider);
- } catch (ClassNotFoundException ignored) {
- // We reach this path is API < 26.
}
- // The DesugarDefaultFileSystemProvider requires the ThreadPolicy to be set to work correctly.
- // We cannot set the ThreadPolicy in headless and it should not matter.
- // In headless, android.os is absent so the following line will throw.
- // In headfull, android.os is present and we set the thread policy.
- try {
- Class.forName("android.os.Build");
+ if (AndroidVersionTest.isHeadfull) {
+ // The DesugarDefaultFileSystemProvider requires the ThreadPolicy to be set to work correctly.
+ // We cannot set the ThreadPolicy in headless and it should not matter.
setThreadPolicy();
- } catch (ClassNotFoundException ignored) {
- // Headless mode.
}
- return DesugarDefaultFileSystemProvider.instance();
+ return DesugarAndroidDefaultFileSystemProvider.instance();
}
private static void setThreadPolicy() {
diff --git a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
index da93736..8980540 100644
--- a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
+++ b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
@@ -17,13 +17,9 @@
private HybridFileTypeDetector() {}
public static FileTypeDetector create() {
- try {
- // On API 26 and above, java.nio.file.Files is present.
- Class.forName("java.nio.file.Files");
- return new PlatformFileTypeDetector();
- } catch (ClassNotFoundException ignored) {
- return DesugarDefaultFileTypeDetector.create();
- }
+ return AndroidVersionTest.is26OrAbove
+ ? new PlatformFileTypeDetector()
+ : DesugarDefaultFileTypeDetector.create();
}
static class PlatformFileTypeDetector extends FileTypeDetector {
diff --git a/src/library_desugar/java/java/nio/channels/DesugarChannels.java b/src/library_desugar/java/java/nio/channels/DesugarChannels.java
new file mode 100644
index 0000000..4ca851d
--- /dev/null
+++ b/src/library_desugar/java/java/nio/channels/DesugarChannels.java
@@ -0,0 +1,242 @@
+// Copyright (c) 2022, 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 java.nio.channels;
+
+import java.adapter.AndroidVersionTest;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileAttribute;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class DesugarChannels {
+
+ /** Special conversion for Channel to answer a converted FileChannel if required. */
+ public static Channel convertMaybeLegacyChannelFromLibrary(Channel raw) {
+ if (raw == null) {
+ return null;
+ }
+ if (raw instanceof FileChannel) {
+ return convertMaybeLegacyFileChannelFromLibrary((FileChannel) raw);
+ }
+ return raw;
+ }
+
+ /**
+ * Below Api 24 FileChannel does not implement SeekableByteChannel. When we get one from the
+ * library, we wrap it to implement the interface.
+ */
+ public static FileChannel convertMaybeLegacyFileChannelFromLibrary(FileChannel raw) {
+ if (raw == null) {
+ return null;
+ }
+ if (AndroidVersionTest.is24OrAbove) {
+ return raw;
+ }
+ return WrappedFileChannel.wrap(raw);
+ }
+
+ /**
+ * We unwrap when going to the library since we cannot intercept the calls to final methods in the
+ * library.
+ */
+ public static FileChannel convertMaybeLegacyFileChannelToLibrary(FileChannel raw) {
+ if (raw == null) {
+ return null;
+ }
+ if (raw instanceof WrappedFileChannel) {
+ return ((WrappedFileChannel) raw).delegate;
+ }
+ return raw;
+ }
+
+ static class WrappedFileChannel extends FileChannel implements SeekableByteChannel {
+
+ final FileChannel delegate;
+
+ public static FileChannel wrap(FileChannel channel) {
+ if (channel instanceof WrappedFileChannel) {
+ return channel;
+ }
+ return new WrappedFileChannel(channel);
+ }
+
+ private WrappedFileChannel(FileChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return delegate.read(dst);
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+ return delegate.read(dsts, offset, length);
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ return delegate.write(src);
+ }
+
+ @Override
+ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ return delegate.write(srcs, offset, length);
+ }
+
+ @Override
+ public long position() throws IOException {
+ return delegate.position();
+ }
+
+ @Override
+ public FileChannel position(long newPosition) throws IOException {
+ return WrappedFileChannel.wrap(delegate.position(newPosition));
+ }
+
+ @Override
+ public long size() throws IOException {
+ return delegate.size();
+ }
+
+ @Override
+ public FileChannel truncate(long size) throws IOException {
+ return WrappedFileChannel.wrap(delegate.truncate(size));
+ }
+
+ @Override
+ public void force(boolean metaData) throws IOException {
+ delegate.force(metaData);
+ }
+
+ @Override
+ public long transferTo(long position, long count, WritableByteChannel target)
+ throws IOException {
+ return delegate.transferTo(position, count, target);
+ }
+
+ @Override
+ public long transferFrom(ReadableByteChannel src, long position, long count)
+ throws IOException {
+ return delegate.transferFrom(src, position, count);
+ }
+
+ @Override
+ public int read(ByteBuffer dst, long position) throws IOException {
+ return delegate.read(dst, position);
+ }
+
+ @Override
+ public int write(ByteBuffer src, long position) throws IOException {
+ return delegate.write(src, position);
+ }
+
+ @Override
+ public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
+ return delegate.map(mode, position, size);
+ }
+
+ @Override
+ public FileLock lock(long position, long size, boolean shared) throws IOException {
+ return delegate.lock(position, size, shared);
+ }
+
+ @Override
+ public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ return delegate.tryLock(position, size, shared);
+ }
+
+ @Override
+ public void implCloseChannel() throws IOException {
+ // We cannot call the protected method, this should be effectively equivalent.
+ delegate.close();
+ }
+ }
+
+ /** The 2 open methods are present to be retargeted from FileChannel#open. */
+ public static FileChannel open(Path path, OpenOption... openOptions) throws IOException {
+ Set<OpenOption> openOptionSet = new HashSet<>();
+ Collections.addAll(openOptionSet, openOptions);
+ return open(path, openOptionSet);
+ }
+
+ public static FileChannel open(
+ Path path, Set<? extends OpenOption> openOptions, FileAttribute<?>... attrs)
+ throws IOException {
+ if (AndroidVersionTest.is26OrAbove) {
+ return FileChannel.open(path, openOptions, attrs);
+ }
+ return openEmulatedFileChannel(path, openOptions, attrs);
+ }
+
+ /**
+ * All FileChannel creation go through the FileSystemProvider which then comes here if the Api is
+ * strictly below 26, and to the plaform FileSystemProvider if the Api is above or equal to 26.
+ *
+ * <p>Below Api 26 there is no way to create a FileChannel, so we create instead an emulated
+ * version using RandomAccessFile which tries, with a best effort, to support all settings.
+ *
+ * <p>The FileAttributes are ignored.
+ */
+ public static FileChannel openEmulatedFileChannel(
+ Path path, Set<? extends OpenOption> openOptions, FileAttribute<?>... attrs)
+ throws IOException {
+
+ validateOpenOptions(path, openOptions);
+
+ RandomAccessFile randomAccessFile =
+ new RandomAccessFile(path.toFile(), getFileAccessModeText(openOptions));
+ if (openOptions.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
+ randomAccessFile.setLength(0);
+ }
+
+ if (!openOptions.contains(StandardOpenOption.APPEND)) {
+ // This one may be retargeted, below 24, to support SeekableByteChannel.
+ return randomAccessFile.getChannel();
+ }
+
+ // TODO(b/259056135): Consider subclassing UnsupportedOperationException for desugared library.
+ // RandomAccessFile does not support APPEND.
+ // We could hack a wrapper to support APPEND in simple cases such as Files.write().
+ throw new UnsupportedOperationException();
+ }
+
+ private static void validateOpenOptions(Path path, Set<? extends OpenOption> openOptions)
+ throws NoSuchFileException {
+ // Validations that resemble sun.nio.fs.UnixChannelFactory#newFileChannel.
+ if (openOptions.contains(StandardOpenOption.READ)
+ && openOptions.contains(StandardOpenOption.APPEND)) {
+ throw new IllegalArgumentException("READ + APPEND not allowed");
+ }
+ if (openOptions.contains(StandardOpenOption.APPEND)
+ && openOptions.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
+ throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
+ }
+ if (openOptions.contains(StandardOpenOption.APPEND) && !path.toFile().exists()) {
+ throw new NoSuchFileException(path.toString());
+ }
+ }
+
+ private static String getFileAccessModeText(Set<? extends OpenOption> options) {
+ if (!options.contains(StandardOpenOption.WRITE)) {
+ return "r";
+ }
+ if (options.contains(StandardOpenOption.SYNC)) {
+ return "rws";
+ }
+ if (options.contains(StandardOpenOption.DSYNC)) {
+ return "rwd";
+ }
+ return "rw";
+ }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
index 91f9a56..46a6562 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
@@ -2,13 +2,57 @@
"configuration_format_version": 5,
"group_id": "com.tools.android",
"artifact_id": "desugar_jdk_libs",
- "version": "1.2.4",
- "required_compilation_api_level": 30,
+ "version": "1.2.5",
+ "required_compilation_api_level": 33,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
"common_flags": [
{
- "api_level_below_or_equal": 10000,
+ "api_level_below_or_equal": 32,
+ "rewrite_prefix": {
+ "java.util.stream.DesugarCollectors": "j$.util.stream.DesugarCollectors"
+ },
+ "retarget_lib_member": {
+ "java.util.stream.Collectors#filtering": "java.util.stream.DesugarCollectors",
+ "java.util.stream.Collectors#flatMapping": "java.util.stream.DesugarCollectors",
+ "java.util.stream.Collectors#toUnmodifiableList": "java.util.stream.DesugarCollectors",
+ "java.util.stream.Collectors#toUnmodifiableMap": "java.util.stream.DesugarCollectors",
+ "java.util.stream.Collectors#toUnmodifiableSet": "java.util.stream.DesugarCollectors"
+ }
+ },
+ {
+ "api_level_below_or_equal": 30,
+ "rewrite_prefix": {
+ "java.time.DesugarDuration": "j$.time.DesugarDuration",
+ "java.time.DesugarLocalTime": "j$.time.DesugarLocalTime"
+ },
+ "retarget_lib_member": {
+ "java.time.Duration#dividedBy": "java.time.DesugarDuration",
+ "java.time.Duration#toDaysPart": "java.time.DesugarDuration",
+ "java.time.Duration#toHoursPart": "java.time.DesugarDuration",
+ "java.time.Duration#toMillisPart": "java.time.DesugarDuration",
+ "java.time.Duration#toMinutesPart": "java.time.DesugarDuration",
+ "java.time.Duration#toNanosPart": "java.time.DesugarDuration",
+ "java.time.Duration#toSeconds": "java.time.DesugarDuration",
+ "java.time.Duration#toSecondsPart": "java.time.DesugarDuration",
+ "java.time.Duration#truncatedTo": "java.time.DesugarDuration",
+ "java.time.LocalTime#ofInstant": "java.time.DesugarLocalTime",
+ "java.time.LocalTime#toEpochSecond": "java.time.DesugarLocalTime"
+ }
+ },
+ {
+ "api_level_below_or_equal": 29,
+ "rewrite_prefix": {
+ "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
+ },
+ "wrapper_conversion": [
+ "java.util.concurrent.Flow$Publisher",
+ "java.util.concurrent.Flow$Subscriber",
+ "java.util.concurrent.Flow$Subscription"
+ ]
+ },
+ {
+ "api_level_below_or_equal": 25,
"rewrite_prefix": {
"java.time.": "j$.time.",
"java.util.Desugar": "j$.util.Desugar"
@@ -34,26 +78,10 @@
}
},
{
- "api_level_below_or_equal": 29,
- "rewrite_prefix": {
- "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
- },
- "wrapper_conversion": [
- "java.util.concurrent.Flow$Publisher",
- "java.util.concurrent.Flow$Subscriber",
- "java.util.concurrent.Flow$Subscription"
- ]
- },
- {
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
- "java.util.function.": "j$.util.function."
- }
- },
- {
- "api_level_below_or_equal": 10000,
- "rewrite_prefix": {
+ "java.util.function.": "j$.util.function.",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -150,7 +178,7 @@
],
"program_flags": [
{
- "api_level_below_or_equal": 10000,
+ "api_level_below_or_equal": 25,
"retarget_lib_member": {
"java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
"java.util.Calendar#toInstant": "java.util.DesugarCalendar",
@@ -180,7 +208,7 @@
],
"library_flags": [
{
- "api_level_below_or_equal": 10000,
+ "api_level_below_or_equal": 25,
"rewrite_prefix": {
"j$.time.": "java.time.",
"java.lang.Desugar": "j$.lang.Desugar",
@@ -196,7 +224,7 @@
}
},
{
- "api_level_below_or_equal": 10000,
+ "api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.util.AbstractList": "j$.util.AbstractList",
"java.util.CollSer": "j$.util.CollSer",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index c97bd79..3295333 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -166,6 +166,7 @@
"java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
"java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
"java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
+ "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
"java.nio.file.": "j$.nio.file."
},
"dont_rewrite_prefix": [
@@ -230,7 +231,8 @@
"java.lang.Iterable java.nio.file.FileSystem#getRootDirectories()": [-1, "java.lang.Iterable java.nio.file.PathApiFlips#flipIterablePath(java.lang.Iterable)"],
"java.util.Iterator java.nio.file.Path#iterator()": [-1, "java.util.Iterator java.nio.file.PathApiFlips#flipIteratorPath(java.util.Iterator)"],
"java.nio.file.DirectoryStream java.nio.file.spi.FileSystemProvider#newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream$Filter)": [-1, "java.nio.file.DirectoryStream java.nio.file.PathApiFlips#flipDirectoryStreamPath(java.nio.file.DirectoryStream)", 1, "java.nio.file.DirectoryStream$Filter java.nio.file.PathApiFlips#flipDirectoryStreamFilterPath(java.nio.file.DirectoryStream$Filter)"],
- "void java.nio.file.spi.FileSystemProvider#setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption[])": [2, "java.lang.Object java.nio.file.FileApiFlips#flipMaybeFileTime(java.lang.Object)"]
+ "void java.nio.file.spi.FileSystemProvider#setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption[])": [2, "java.lang.Object java.nio.file.FileApiFlips#flipMaybeFileTime(java.lang.Object)"],
+ "java.nio.channels.FileChannel java.nio.channels.FileChannel#open(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])" : [1, "java.util.Set java.nio.file.FileApiFlips#flipOpenOptionSet(java.util.Set)"]
},
"wrapper_conversion": [
"java.nio.channels.CompletionHandler",
@@ -279,8 +281,6 @@
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
- "java.nio.channels.FileChannel": "j$.nio.channels.FileChannel",
- "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -294,12 +294,10 @@
"java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
"java.util.stream.": "j$.util.stream."
},
- "dont_rewrite_prefix": [
- "java.nio.channels.FileChannel$MapMode"
- ],
"maintain_prefix": [
"java.util.function.",
- "java.io.UncheckedIOException"
+ "java.io.UncheckedIOException",
+ "java.nio.channels.SeekableByteChannel"
],
"emulate_interface": {
"java.lang.Iterable": "j$.lang.Iterable",
@@ -347,13 +345,18 @@
"java.util.stream.IntStream java.util.stream.IntStream#flatMap(java.util.function.IntFunction)": [0, "java.util.function.IntFunction java.util.stream.FlatMapApiFlips#flipFunctionReturningStream(java.util.function.IntFunction)"],
"java.util.stream.LongStream java.util.stream.Stream#flatMapToLong(java.util.function.Function)": [0, "java.util.function.Function java.util.stream.FlatMapApiFlips#flipFunctionReturningStream(java.util.function.Function)"],
"java.util.stream.LongStream java.util.stream.LongStream#flatMap(java.util.function.LongFunction)": [0, "java.util.function.LongFunction java.util.stream.FlatMapApiFlips#flipFunctionReturningStream(java.util.function.LongFunction)"],
- "java.lang.Object java.lang.StackWalker#walk(java.util.function.Function)": [0, "java.util.function.Function java.util.stream.StackWalkerApiFlips#flipFunctionStream(java.util.function.Function)"]
+ "java.lang.Object java.lang.StackWalker#walk(java.util.function.Function)": [0, "java.util.function.Function java.util.stream.StackWalkerApiFlips#flipFunctionStream(java.util.function.Function)"],
+ "java.nio.channels.FileChannel java.nio.channels.FileLock#channel()": [-1, "java.nio.channels.FileChannel java.nio.channels.DesugarChannels#convertMaybeLegacyFileChannelFromLibrary(java.nio.channels.FileChannel)"],
+ "java.nio.channels.Channel java.nio.channels.FileLock#acquiredBy()": [-1, "java.nio.channels.Channel java.nio.channels.DesugarChannels#convertMaybeLegacyChannelFromLibrary(java.nio.channels.Channel)"],
+ "java.nio.channels.FileChannel java.io.RandomAccessFile#getChannel()": [-1, "java.nio.channels.FileChannel java.nio.channels.DesugarChannels#convertMaybeLegacyFileChannelFromLibrary(java.nio.channels.FileChannel)"],
+ "java.nio.channels.FileChannel java.io.FileInputStream#getChannel()": [-1, "java.nio.channels.FileChannel java.nio.channels.DesugarChannels#convertMaybeLegacyFileChannelFromLibrary(java.nio.channels.FileChannel)"],
+ "java.nio.channels.FileChannel java.io.FileOutputStream#getChannel()": [-1, "java.nio.channels.FileChannel java.nio.channels.DesugarChannels#convertMaybeLegacyFileChannelFromLibrary(java.nio.channels.FileChannel)"],
+ "void java.nio.channels.FileLock#<init>(java.nio.channels.FileChannel,long, long, boolean)": [0, "java.nio.channels.FileChannel java.nio.channels.DesugarChannels#convertMaybeLegacyFileChannelToLibrary(java.nio.channels.FileChannel)"]
},
"never_outline_api": [
"java.lang.Object java.lang.StackWalker#walk(java.util.function.Function)"
],
"wrapper_conversion": [
- "java.nio.channels.SeekableByteChannel",
"java.util.PrimitiveIterator$OfDouble",
"java.util.PrimitiveIterator$OfInt",
"java.util.PrimitiveIterator$OfLong",
@@ -370,18 +373,6 @@
"java.util.stream.LongStream",
"java.util.stream.Stream"
],
- "wrapper_conversion_excluding": {
- "java.nio.channels.FileChannel": [
- "long java.nio.channels.FileChannel#read(java.nio.ByteBuffer[])",
- "long java.nio.channels.FileChannel#write(java.nio.ByteBuffer[])",
- "java.nio.channels.FileLock java.nio.channels.FileChannel#lock()",
- "java.nio.channels.FileLock java.nio.channels.FileChannel#tryLock()",
- "void java.nio.channels.spi.AbstractInterruptibleChannel#close()",
- "boolean java.nio.channels.spi.AbstractInterruptibleChannel#isOpen()",
- "void java.nio.channels.spi.AbstractInterruptibleChannel#begin()",
- "void java.nio.channels.spi.AbstractInterruptibleChannel#end(boolean)"
- ]
- },
"custom_conversion": {
"java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions",
"java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
@@ -442,7 +433,9 @@
"java.time.Instant java.util.Calendar#toInstant()": "java.util.DesugarCalendar",
"java.util.Date java.util.Date#from(java.time.Instant)": "java.util.DesugarDate",
"java.util.GregorianCalendar java.util.GregorianCalendar#from(java.time.ZonedDateTime)": "java.util.DesugarGregorianCalendar",
- "java.util.TimeZone java.util.TimeZone#getTimeZone(java.lang.String)": "java.util.DesugarTimeZone"
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.lang.String)": "java.util.DesugarTimeZone",
+ "java.nio.channels.FileChannel java.nio.channels.FileChannel#open(java.nio.file.Path, java.nio.file.OpenOption[])": "java.nio.channels.DesugarChannels",
+ "java.nio.channels.FileChannel java.nio.channels.FileChannel#open(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])": "java.nio.channels.DesugarChannels"
}
},
{
@@ -483,7 +476,6 @@
{
"api_level_below_or_equal": 25,
"rewrite_prefix": {
- "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
"jdk.internal.": "j$.jdk.internal.",
"sun.misc.Desugar": "j$.sun.misc.Desugar",
"sun.nio.cs.": "j$.sun.nio.cs.",
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 6754dde..4649132 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -141,10 +141,12 @@
private final Set<DexLibraryClass> libraryClassesToMock = Sets.newConcurrentHashSet();
private final Set<DexType> seenTypes = Sets.newConcurrentHashSet();
private final AndroidApiLevelCompute apiLevelCompute;
+ private final DexItemFactory factory;
public ApiReferenceStubber(AppView<?> appView) {
this.appView = appView;
apiLevelCompute = appView.apiLevelCompute();
+ factory = appView.dexItemFactory();
}
public void run(ExecutorService executorService) throws ExecutionException {
@@ -228,6 +230,12 @@
|| libraryClass.getType().toDescriptorString().startsWith("Ljava/")) {
return;
}
+ // We cannot reliably create a stub that will have the same throwing
+ // behavior for all VMs. We only create stubs for exceptions to allow them being present in
+ // catch handlers. See b/b/258270051 for more information.
+ if (!isThrowable(libraryClass)) {
+ return;
+ }
if (appView
.options()
.machineDesugaredLibrarySpecification
@@ -259,7 +267,6 @@
.setProto(factory.createProto(factory.voidType))
.setAccessFlags(MethodAccessFlags.createForClassInitializer())
.setCode(method -> throwExceptionCode));
- // Based on b/138781768#comment57 there is no significant reason to synthesize fields.
if (libraryClass.isInterface()) {
classBuilder.setInterface();
}
@@ -269,4 +276,16 @@
},
ignored -> {});
}
+
+ private boolean isThrowable(DexLibraryClass libraryClass) {
+ DexClass current = libraryClass;
+ while (current.getSuperType() != null) {
+ DexType superType = current.getSuperType();
+ if (superType == factory.throwableType) {
+ return true;
+ }
+ current = appView.definitionFor(current.getSuperType());
+ }
+ return false;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 5869f46..65572c8 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -75,9 +75,8 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
@@ -112,7 +111,7 @@
private final List<List<LocalVariableInfo>> localsAtLabel;
private final StringBuilder builder = new StringBuilder();
- private final ClassNameMapper mapper;
+ private final RetracerForCodePrinting retracer;
private int nextInstructionIndex = 0;
private final int instructionIndexSpace;
@@ -121,7 +120,7 @@
public CfPrinter() {
indent = "";
labelToIndex = null;
- mapper = null;
+ retracer = RetracerForCodePrinting.empty();
instructionIndexSpace = 0;
sortedLabels = Collections.emptyList();
@@ -130,12 +129,12 @@
/** Entry for printing a complete code object. */
public CfPrinter(CfCode code) {
- this(code, null, null);
+ this(code, null, RetracerForCodePrinting.empty());
}
/** Entry for printing a complete method object. */
- public CfPrinter(CfCode code, DexEncodedMethod method, ClassNameMapper mapper) {
- this.mapper = mapper;
+ public CfPrinter(CfCode code, DexEncodedMethod method, RetracerForCodePrinting retracer) {
+ this.retracer = retracer;
indent = " ";
instructionIndexSpace = ("" + code.getInstructions().size()).length();
labelToIndex = new Reference2IntOpenHashMap<>();
@@ -770,56 +769,36 @@
}
private void appendDescriptor(DexType type) {
- if (mapper != null) {
- builder.append(DescriptorUtils.javaTypeToDescriptor(mapper.originalNameOf(type)));
- return;
- }
- builder.append(type.toDescriptorString());
+ builder.append(retracer.toDescriptor(type));
}
private void appendType(DexType type) {
if (type.isArrayType() || type.isClassType()) {
appendClass(type);
} else {
- builder.append(type);
+ builder.append(retracer.toDescriptor(type));
}
}
private void appendTypeElement(TypeElement type) {
- builder.append(type.toString());
+ builder.append(type);
}
private void appendClass(DexType type) {
assert type.isArrayType() || type.isClassType();
- if (mapper == null) {
- builder.append(type.getInternalName());
- } else if (type == DexItemFactory.nullValueType) {
+ if (type == DexItemFactory.nullValueType) {
builder.append("NULL");
} else {
- builder.append(
- DescriptorUtils.descriptorToInternalName(
- DescriptorUtils.javaTypeToDescriptor(mapper.originalNameOf(type))));
+ builder.append(retracer.toDescriptor(type));
}
}
private void appendField(DexField field) {
- if (mapper != null) {
- builder.append(mapper.originalSignatureOf(field).toString());
- return;
- }
- appendClass(field.holder);
- builder.append('/').append(field.name);
+ builder.append(retracer.toDescriptor(field));
}
private void appendMethod(DexMethod method) {
- if (mapper != null) {
- MethodSignature signature = mapper.originalSignatureOf(method);
- builder.append(mapper.originalNameOf(method.holder)).append('.');
- builder.append(signature.name).append(signature.toDescriptor());
- return;
- }
- builder.append(method.qualifiedName());
- builder.append(method.proto.toDescriptorString());
+ builder.append(retracer.toDescriptor(method));
}
private String opcodeName(int opcode) {
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConst.java b/src/main/java/com/android/tools/r8/dex/code/DexConst.java
index 33fdff4..c47c264 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConst.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.SingleConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConst extends DexFormat31i implements SingleConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConst16.java b/src/main/java/com/android/tools/r8/dex/code/DexConst16.java
index 1188df2..d676e03 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConst16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst16.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.SingleConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConst16 extends DexFormat21s implements SingleConstant {
@@ -44,7 +44,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 4) + " (" + decodedValue() + ")");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConst4.java b/src/main/java/com/android/tools/r8/dex/code/DexConst4.java
index 09ecd15..f1dd41c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConst4.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConst4.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.SingleConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConst4 extends DexFormat11n implements SingleConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + A + ", " + StringUtils.hexString(decodedValue(), 1) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + A + ", " + StringUtils.hexString(decodedValue(), 2) + " # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
index 2e732ed..82a6aa3 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstHigh16.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.SingleConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConstHigh16 extends DexFormat21h implements SingleConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 8) + " # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
index 87964c8..b909f64 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodHandle.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
@@ -58,12 +58,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
index 68f49fb..15bee8c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstMethodType.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
@@ -57,12 +57,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
index 0117785..e143d89 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstString.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
@@ -75,12 +75,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java b/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
index 725ef8a..e1811ba 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstStringJumbo.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public class DexConstStringJumbo extends DexFormat31c {
@@ -52,12 +52,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", \"" + BBBBBBBB.toString() + "\"");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", \"" + BBBBBBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
index 6fbd6f2..899e221 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConstWide extends DexFormat51l implements WideConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + "L # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
index e30b886..2cd5ae3 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide16.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConstWide16 extends DexFormat21s implements WideConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + "L # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
index b315cb9..9797a19 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWide32.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConstWide32 extends DexFormat31i implements WideConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java b/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
index 0eeca93..93b7f34 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexConstWideHigh16.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.WideConstant;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
public class DexConstWideHigh16 extends DexFormat21h implements WideConstant {
@@ -44,13 +44,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + " (" + decodedValue() + ")");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", " + StringUtils.hexString(decodedValue(), 16) + "L # " + decodedValue());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
index de478d7..0a3974d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayData.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.dex.code;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public class DexFillArrayData extends DexFormat31t {
@@ -41,7 +41,7 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", :label_" + (getOffset() + BBBBBBBB));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
index 67d796c..228258d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFillArrayDataPayload.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -91,8 +91,8 @@
}
@Override
- public String toString(ClassNameMapper naming) {
- return super.toString(naming)
+ public String toString(RetracerForCodePrinting retracer) {
+ return super.toString(retracer)
+ "[FillArrayPayload], "
+ "width: "
+ element_width
@@ -101,7 +101,7 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
builder.append(" ");
builder.append(".array-data ");
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
index ba9065a..ba29cbe 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10t.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
@@ -56,12 +56,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(formatRelativeOffset(AA));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(":label_" + (getOffset() + AA));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
index 3cb41fb..174c89b 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat10x.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import java.nio.ShortBuffer;
abstract class DexFormat10x extends DexBase1Format {
@@ -33,12 +33,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(null);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(null);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
index fe02384..09e3fb6 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11n.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -70,7 +70,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + A + ", #" + B);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
index b07478c..393ab88 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat11x.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
@@ -56,12 +56,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
index 633837d..979bcc7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat12x.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -64,12 +64,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + A + ", v" + B);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + A + ", v" + B);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
index 0c0e15e..a03b9c5 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat20t.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
@@ -56,12 +56,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("" + AAAA + " " + formatRelativeOffset(AAAA));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(":label_" + (getOffset() + AAAA));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
index b47c6d7..4d25775 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21c.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -52,13 +52,12 @@
abstract void internalSubSpecify(StructuralSpecification<DexFormat21c<T>, ?> spec);
@Override
- public String toString(ClassNameMapper naming) {
- return formatString(
- "v" + AA + ", " + (naming == null ? BBBB.toString() : naming.originalNameOf(BBBB)));
+ public String toString(RetracerForCodePrinting retracer) {
+ return formatString("v" + AA + ", " + retracer.toDescriptor(BBBB));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
// TODO(sgjesse): Add support for smali name mapping.
return formatSmaliString("v" + AA + ", " + BBBB.toSmaliString());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
index 97e3529..3d66ad2 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21s.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -67,12 +67,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", #" + BBBB);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", " + StringUtils.hexString(BBBB, 4) + " # " + BBBB);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
index 1c80b33..93cd025 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat21t.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -85,12 +85,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", " + formatRelativeOffset(BBBB));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", :label_" + (getOffset() + BBBB));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
index 687d7e7..222fc09 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22b.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -71,12 +71,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", v" + BB + ", #" + CC);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + AA + ", v" + BB + ", " + StringUtils.hexString(CC, 2) + " # " + CC);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
index 2e1246c..68c7839 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22c.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -57,13 +57,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
- return formatString(
- "v" + A + ", v" + B + ", " + (naming == null ? CCCC : naming.originalNameOf(CCCC)));
+ public String toString(RetracerForCodePrinting retracer) {
+ return formatString("v" + A + ", v" + B + ", " + retracer.toDescriptor(CCCC));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
// TODO(sgjesse): Add support for smali name mapping.
return formatSmaliString("v" + A + ", v" + B + ", " + CCCC.toSmaliString());
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
index e503467..53d247c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22s.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -71,12 +71,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + A + ", v" + B + ", #" + CCCC);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(
"v" + A + ", v" + B + ", " + StringUtils.hexString(CCCC, 4) + " # " + CCCC);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
index 17695d7..c276ca1 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22t.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -89,12 +89,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + A + ", v" + B + ", " + formatRelativeOffset(CCCC));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + A + ", v" + B + ", :label_" + (getOffset() + CCCC));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
index 3c34540..3cd881d 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat22x.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -66,12 +66,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", v" + (int) BBBB);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", v" + (int) BBBB);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
index df098d9..1e1b130 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat23x.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -70,12 +70,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", v" + BB + ", v" + CC);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", v" + BB + ", v" + CC);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
index aa744ad..cfd2bf7 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat30t.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
@@ -55,12 +55,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString(formatOffset(AAAAAAAA));
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString(":label_" + (getOffset() + AAAAAAAA));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
index 8023664..ae0ca6c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31c.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -69,9 +69,8 @@
}
@Override
- public String toString(ClassNameMapper naming) {
- return formatString(
- "v" + AA + ", " + (naming == null ? BBBBBBBB : naming.originalNameOf(BBBBBBBB)));
+ public String toString(RetracerForCodePrinting retracer) {
+ return formatString("v" + AA + ", " + retracer.toDescriptor(BBBBBBBB));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
index 0795a92..942c5e2 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31i.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -65,7 +65,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", #" + BBBBBBBB);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
index 320514d..7f26c21 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat31t.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -80,7 +80,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", " + formatRelativeOffset(BBBBBBBB));
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
index 00cf1f4..5389c2f 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat32x.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -68,12 +68,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AAAA + ", v" + BBBB);
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AAAA + ", v" + BBBB);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
index 6e40c73..0f195c1 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat35c.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -94,20 +94,16 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, " ");
builder.append(" ");
- if (naming == null) {
- builder.append(BBBB.toSmaliString());
- } else {
- builder.append(naming.originalNameOf(BBBB));
- }
+ builder.append(retracer.toDescriptor(BBBB));
return formatString(builder.toString());
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, ", ");
builder.append(", ");
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
index b0c0204..3d8289c 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat3rc.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -71,20 +71,16 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterRange(builder);
builder.append(" ");
- if (naming == null) {
- builder.append(BBBB.toSmaliString());
- } else {
- builder.append(naming.originalNameOf(BBBB));
- }
+ builder.append(retracer.toDescriptor(BBBB));
return formatString(builder.toString());
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterRange(builder);
builder.append(", ");
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
index 61a0257..2f4adc5 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat45cc.java
@@ -11,12 +11,11 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
-import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -137,7 +136,7 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, ", ");
builder.append(", ");
@@ -149,26 +148,16 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterArguments(builder, " ");
builder.append(" ");
- builder.append(itemToString(BBBB, naming));
+ builder.append(retracer.toDescriptor(BBBB));
builder.append(", ");
- builder.append(itemToString(HHHH, naming));
+ builder.append(retracer.toDescriptor(HHHH));
return formatString(builder.toString());
}
- private String itemToString(IndexedDexItem indexedDexItem, ClassNameMapper naming) {
- String str;
- if (naming == null) {
- str = indexedDexItem.toSmaliString();
- } else {
- str = naming.originalNameOf(indexedDexItem);
- }
- return str;
- }
-
private void appendRegisterArguments(StringBuilder builder, String separator) {
builder.append("{ ");
int[] values = new int[] {C, D, E, F, G};
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
index b795316..8aa065a 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat4rcc.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -90,25 +90,17 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterRange(builder);
builder.append(" ");
- if (naming == null) {
- builder.append(BBBB.toSmaliString());
- } else {
- builder.append(naming.originalNameOf(BBBB));
- }
- if (naming == null) {
- builder.append(HHHH.toSmaliString());
- } else {
- builder.append(naming.originalNameOf(HHHH));
- }
+ builder.append(retracer.toDescriptor(BBBB));
+ builder.append(retracer.toDescriptor(HHHH));
return formatString(builder.toString());
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
appendRegisterRange(builder);
builder.append(", ");
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
index 30ddee5..ddce5ad 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexFormat51l.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -65,7 +65,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
return formatString("v" + AA + ", #" + BBBBBBBBBBBBBBBB);
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
index c600656..8591fd9 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.ir.code.FieldMemberType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -144,18 +144,12 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + dest + ", " + clazz.toSmaliString());
}
@Override
- public String toString(ClassNameMapper naming) {
- StringBuilder builder = new StringBuilder("v").append(dest).append(", ");
- if (naming == null) {
- builder.append(clazz.toSourceString());
- } else {
- builder.append(naming.originalNameOf(clazz));
- }
- return formatString(builder.toString());
+ public String toString(RetracerForCodePrinting retracer) {
+ return formatString("v" + dest + ", " + retracer.toDescriptor(clazz));
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
index d5f8183..e6362d0 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexInstruction.java
@@ -19,7 +19,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.Equatable;
@@ -372,21 +372,21 @@
throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user");
}
- public abstract String toSmaliString(ClassNameMapper naming);
+ public abstract String toSmaliString(RetracerForCodePrinting retracer);
public String toSmaliString() {
- return toSmaliString((ClassNameMapper) null);
+ return toSmaliString((RetracerForCodePrinting) null);
}
- public abstract String toString(ClassNameMapper naming);
+ public abstract String toString(RetracerForCodePrinting retracer);
- public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
+ public String toString(RetracerForCodePrinting retracer, DexInstruction payloadUser) {
throw new InternalCompilerError("Instruction " + payloadUser + " is not a payload user");
}
@Override
public String toString() {
- return toString(null);
+ return toString(RetracerForCodePrinting.empty());
}
public abstract void write(
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
index d34a783..ddaf074 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexItemBasedConstString.java
@@ -13,8 +13,8 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
@@ -85,13 +85,13 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
// TODO(christofferqa): Apply mapping to item.
return formatString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
// TODO(christofferqa): Apply mapping to item.
return formatSmaliString("v" + AA + ", \"" + BBBB.toString() + "\"");
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
index 34029d8..c00a3b4 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitch.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.dex.code;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public class DexPackedSwitch extends DexFormat31t {
@@ -50,7 +50,7 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", :label_" + (getOffset() + BBBBBBBB));
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
index d06f619..95f6eed 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexPackedSwitchPayload.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -102,12 +102,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
- return toString(naming, null);
+ public String toString(RetracerForCodePrinting retracer) {
+ return toString(retracer, null);
}
@Override
- public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
+ public String toString(RetracerForCodePrinting retracer, DexInstruction payloadUser) {
StringBuilder builder = new StringBuilder("[PackedSwitchPayload");
if (payloadUser == null) {
builder.append(" offsets relative to associated PackedSwitch");
@@ -123,7 +123,7 @@
}
StringUtils.appendLeftPadded(builder, (first_key + i) + " -> " + offsetString + "\n", 20);
}
- return super.toString(naming) + builder.toString();
+ return super.toString(retracer) + builder.toString();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
index 955f67e..3101663 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexRecordFieldValues.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -100,7 +100,7 @@
}
@Override
- public String toString(ClassNameMapper naming) {
+ public String toString(RetracerForCodePrinting retracer) {
StringBuilder sb = new StringBuilder();
sb.append("v").append(outRegister).append(" ");
appendArguments(sb);
@@ -108,8 +108,8 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
- return toString(naming);
+ public String toSmaliString(RetracerForCodePrinting retracer) {
+ return toString(retracer);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
index 4f15ab7..8dfabb6 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitch.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.dex.code;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public class DexSparseSwitch extends DexFormat31t {
@@ -49,7 +49,7 @@
}
@Override
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
return formatSmaliString("v" + AA + ", :label_" + (getOffset() + BBBBBBBB));
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
index 97d369a..838e4ea 100644
--- a/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/dex/code/DexSparseSwitchPayload.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -108,12 +108,12 @@
}
@Override
- public String toString(ClassNameMapper naming) {
- return toString(naming, null);
+ public String toString(RetracerForCodePrinting retracer) {
+ return toString(retracer, null);
}
@Override
- public String toString(ClassNameMapper naming, DexInstruction payloadUser) {
+ public String toString(RetracerForCodePrinting retracer, DexInstruction payloadUser) {
StringBuilder builder = new StringBuilder("[SparseSwitchPayload");
if (payloadUser == null) {
builder.append(" offsets relative to associated SparseSwitch");
@@ -129,7 +129,7 @@
}
StringUtils.appendLeftPadded(builder, keys[i] + " -> " + offsetString + "\n", 20);
}
- return super.toString(naming) + builder.toString();
+ return super.toString(retracer) + builder.toString();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 369e60c..4b70a1c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -275,8 +275,8 @@
public boolean isSubtype(DexType subtype, DexType supertype) {
assert subtype != null;
assert supertype != null;
- assert subtype.isClassType();
- assert supertype.isClassType();
+ assert subtype.isClassType() : "subtype not a class: " + subtype;
+ assert supertype.isClassType() : "supertype not a class: " + supertype;
return subtype == supertype || isStrictSubtypeOf(subtype, supertype);
}
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 3061f1b..43ee151 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -12,11 +12,12 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.StringUtils.BraceType;
import com.android.tools.r8.utils.Timing;
import java.io.BufferedReader;
import java.io.PrintStream;
@@ -34,6 +35,7 @@
private final Kotlin kotlin;
private final Timing timing = new Timing("AssemblyWriter");
private final CompilationContext compilationContext;
+ private final RetracerForCodePrinting retracer;
public AssemblyWriter(
DexApplication application,
@@ -62,6 +64,8 @@
this.appInfo = null;
}
kotlin = new Kotlin(application.dexItemFactory);
+ retracer =
+ RetracerForCodePrinting.create(application.getProguardMap(), application.options.reporter);
}
public static String getFileEnding() {
@@ -70,22 +74,17 @@
@Override
void writeClassHeader(DexProgramClass clazz, PrintStream ps) {
- String clazzName;
- if (application.getProguardMap() != null) {
- clazzName = application.getProguardMap().originalNameOf(clazz.type);
- } else {
- clazzName = clazz.type.toSourceString();
- }
+ String clazzName = retracer.toSourceString(clazz.getType());
ps.println("# Bytecode for");
ps.println("# Class: '" + clazzName + "'");
if (writeAllClassInfo) {
writeAnnotations(clazz, clazz.annotations(), ps);
ps.println("# Flags: '" + clazz.accessFlags + "'");
if (clazz.superType != application.dexItemFactory.objectType) {
- ps.println("# Extends: '" + clazz.superType.toSourceString() + "'");
+ ps.println("# Extends: '" + retracer.toSourceString(clazz.superType) + "'");
}
for (DexType value : clazz.interfaces.values) {
- ps.println("# Implements: '" + value.toSourceString() + "'");
+ ps.println("# Implements: '" + retracer.toSourceString(value) + "'");
}
if (!clazz.getInnerClasses().isEmpty()) {
ps.println("# InnerClasses:");
@@ -93,10 +92,10 @@
ps.println(
"# Outer: "
+ (innerClassAttribute.getOuter() != null
- ? innerClassAttribute.getOuter().toSourceString()
+ ? retracer.toSourceString(innerClassAttribute.getOuter())
: "-")
+ ", inner: "
- + innerClassAttribute.getInner().toSourceString()
+ + retracer.toSourceString(innerClassAttribute.getInner())
+ ", inner name: "
+ innerClassAttribute.getInnerName()
+ ", access: "
@@ -107,10 +106,12 @@
if (enclosingMethodAttribute != null) {
ps.println("# EnclosingMethod:");
if (enclosingMethodAttribute.getEnclosingClass() != null) {
- ps.println("# Class: " + enclosingMethodAttribute.getEnclosingClass().toSourceString());
+ ps.println(
+ "# Class: " + retracer.toSourceString(enclosingMethodAttribute.getEnclosingClass()));
} else {
ps.println(
- "# Method: " + enclosingMethodAttribute.getEnclosingMethod().toSourceString());
+ "# Method: "
+ + retracer.toSourceString(enclosingMethodAttribute.getEnclosingMethod()));
}
}
}
@@ -129,14 +130,9 @@
@Override
void writeField(DexEncodedField field, PrintStream ps) {
if (writeFields) {
- ClassNameMapper naming = application.getProguardMap();
- FieldSignature fieldSignature =
- naming != null
- ? naming.originalSignatureOf(field.getReference())
- : FieldSignature.fromDexField(field.getReference());
writeAnnotations(null, field.annotations(), ps);
ps.print(field.accessFlags + " ");
- ps.print(fieldSignature);
+ ps.print(retracer.toSourceString(field.getReference()));
if (field.isStatic() && field.hasExplicitStaticValue()) {
ps.print(" = " + field.getStaticValue());
}
@@ -152,15 +148,13 @@
@Override
void writeMethod(ProgramMethod method, PrintStream ps) {
DexEncodedMethod definition = method.getDefinition();
- ClassNameMapper naming = application.getProguardMap();
- String methodName =
- naming != null
- ? naming.originalSignatureOf(method.getReference()).name
- : method.getReference().name.toString();
ps.println("#");
- ps.println("# Method: '" + methodName + "':");
+ ps.println("# Method: '" + retracer.toSourceString(definition.getReference()) + "':");
writeAnnotations(null, definition.annotations(), ps);
ps.println("# " + definition.accessFlags);
+ if (!retracer.isEmpty()) {
+ ps.println("# Residual: '" + definition.getReference().toSourceString());
+ }
ps.println("#");
ps.println();
if (!writeCode) {
@@ -171,7 +165,7 @@
if (writeIR) {
writeIR(method, ps);
} else {
- ps.println(code.toString(definition, naming));
+ ps.println(code.toString(definition, retracer));
}
}
}
@@ -188,7 +182,7 @@
OptimizationFeedbackIgnore.getInstance(),
methodProcessor,
methodProcessingContext));
- ps.println(printer.toString());
+ ps.println(printer);
}
private void writeAnnotations(
@@ -202,9 +196,19 @@
assert clazz != null : "Kotlin metadata is a class annotation";
KotlinMetadataWriter.writeKotlinMetadataAnnotation(prefix, annotation, ps, kotlin);
} else {
- String annotationString = annotation.toString();
+ StringBuilder sb = new StringBuilder();
+ sb.append(annotation.getVisibility());
+ sb.append(" ");
+ sb.append(retracer.toSourceString(annotation.getAnnotationType()));
+ sb.append(
+ StringUtils.join(
+ ",",
+ annotation.annotation.elements,
+ element ->
+ element.getName().toString() + " = " + getStringValue(element.getValue()),
+ BraceType.SQUARE));
ps.print(
- new BufferedReader(new StringReader(annotationString))
+ new BufferedReader(new StringReader(sb.toString()))
.lines()
.collect(
Collectors.joining(
@@ -215,6 +219,26 @@
}
}
+ private String getStringValue(DexValue value) {
+ if (value.isDexValueType()) {
+ return retracer.toSourceString(value.asDexValueType().getValue());
+ } else if (value.isDexValueMethodHandle()) {
+ return retracer.toSourceString(value.asDexValueMethodHandle().value.asMethod());
+ } else if (value.isDexValueMethod()) {
+ return retracer.toSourceString(value.asDexValueMethod().value);
+ } else if (value.isDexItemBasedValueString()) {
+ return retracer.toSourceString(value.asDexItemBasedValueString().value);
+ } else if (value.isDexValueEnum()) {
+ return retracer.toSourceString(value.asDexValueEnum().value);
+ } else if (value.isDexValueField()) {
+ return retracer.toSourceString(value.asDexValueField().value);
+ } else if (value.isDexValueArray()) {
+ return "[" + value.asDexValueArray() + "]";
+ } else {
+ return value.toString();
+ }
+ }
+
@Override
void writeClassFooter(DexProgramClass clazz, PrintStream ps) {
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 f415e4b..63d7d65 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -38,11 +38,11 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -783,8 +783,8 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
- return new CfPrinter(this, method, naming).toString();
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
+ return new CfPrinter(this, method, retracer).toString();
}
public ConstraintWithTarget computeInliningConstraint(
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 0edeb6f..1077fb9 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -13,8 +13,8 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
public abstract class Code extends CachedHashValueDexItem {
@@ -71,7 +71,7 @@
@Override
public abstract String toString();
- public abstract String toString(DexEncodedMethod method, ClassNameMapper naming);
+ public abstract String toString(DexEncodedMethod method, RetracerForCodePrinting retracer);
public boolean isCfCode() {
return false;
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index 425c5d5..165ff81 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -28,10 +28,10 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.IteratorUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.google.common.collect.ImmutableList;
import java.nio.ShortBuffer;
@@ -391,7 +391,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return toString();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 924590f..aff4bff 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -101,6 +101,10 @@
return visibility + " " + annotation;
}
+ public int getVisibility() {
+ return visibility;
+ }
+
public void collectIndexedItems(AppView<?> appView, IndexedItemCollection indexedItems) {
annotation.collectIndexedItems(appView, indexedItems);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
index a2be262..aa6aaec 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -71,4 +71,7 @@
assert false;
}
+ public DexString getName() {
+ return name;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index ad59604..7e55f8e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -27,9 +27,9 @@
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.structural.Equatable;
import com.android.tools.r8.utils.structural.HashCodeVisitor;
@@ -449,14 +449,14 @@
@Override
public String toString() {
- return toString(null, null);
+ return toString(null, RetracerForCodePrinting.empty());
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
if (method != null) {
- builder.append(method.toSourceString()).append("\n");
+ builder.append(retracer.toSourceString(method.getReference())).append("\n");
}
builder.append("registers: ").append(registerSize);
builder.append(", inputs: ").append(incomingRegisterSize);
@@ -495,9 +495,9 @@
builder.append(": ");
if (insn.isSwitchPayload()) {
DexInstruction payloadUser = payloadUsers.get(insn.getOffset());
- builder.append(insn.toString(naming, payloadUser));
+ builder.append(insn.toString(retracer, payloadUser));
} else {
- builder.append(insn.toString(naming));
+ builder.append(insn.toString(retracer));
}
builder.append('\n');
}
@@ -542,7 +542,7 @@
return current;
}
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
// Find labeled targets.
Map<Integer, DexInstruction> payloadUsers = new HashMap<>();
@@ -582,7 +582,7 @@
DexInstruction payloadUser = payloadUsers.get(dex.getOffset());
builder.append(dex.toSmaliString(payloadUser)).append('\n');
} else {
- builder.append(dex.toSmaliString(naming)).append('\n');
+ builder.append(dex.toSmaliString(retracer)).append('\n');
}
}
if (tries.length > 0) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 985e215..318b353 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -56,7 +56,6 @@
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.NamingLens;
@@ -65,6 +64,7 @@
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.Ordered;
@@ -902,7 +902,7 @@
this.parameterAnnotationsList = parameterAnnotations;
}
- public String toSmaliString(ClassNameMapper naming) {
+ public String toSmaliString(RetracerForCodePrinting naming) {
checkIfObsolete();
StringBuilder builder = new StringBuilder();
builder.append(".method ");
@@ -1226,7 +1226,7 @@
public String codeToString() {
checkIfObsolete();
- return code == null ? "<no code>" : code.toString(this, null);
+ return code == null ? "<no code>" : code.toString(this, RetracerForCodePrinting.empty());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 36c45bc..e0e2bd6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -56,6 +57,10 @@
return Reference.classFromDescriptor(toDescriptorString());
}
+ public TypeReference asTypeReference() {
+ return Reference.typeFromDescriptor(toDescriptorString());
+ }
+
public DynamicTypeWithUpperBound toDynamicType(AppView<AppInfoWithLiveness> appView) {
return toDynamicType(appView, Nullability.maybeNull());
}
diff --git a/src/main/java/com/android/tools/r8/graph/InvalidCode.java b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
index 2b9de26..b3016c9 100644
--- a/src/main/java/com/android/tools/r8/graph/InvalidCode.java
+++ b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
@@ -6,8 +6,8 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public class InvalidCode extends Code {
@@ -48,7 +48,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
StringBuilder builder = new StringBuilder();
if (method != null) {
builder.append(method.toSourceString()).append("\n");
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index d18e823..3ab128b 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -63,7 +63,6 @@
import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.position.TextPosition;
@@ -74,6 +73,7 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringDiagnostic;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -295,8 +295,8 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
- return asCfCode().toString(method, naming);
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
+ return asCfCode().toString(method, retracer);
}
protected BiFunction<String, String, LazyCfCode> createCodeLocator(ReparseContext context) {
diff --git a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
index edf7d58..0eff9d1 100644
--- a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.Timing;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -31,7 +32,7 @@
} catch (IOException e) {
throw new CompilationError("Failed to generate smali sting", e);
}
- return new String(os.toByteArray(), StandardCharsets.UTF_8);
+ return os.toString(StandardCharsets.UTF_8);
}
public static String getFileEnding() {
@@ -67,7 +68,12 @@
@Override
void writeMethod(ProgramMethod method, PrintStream ps) {
ps.append("\n");
- ps.append(method.getDefinition().toSmaliString(application.getProguardMap()));
+ ps.append(
+ method
+ .getDefinition()
+ .toSmaliString(
+ RetracerForCodePrinting.create(
+ application.getProguardMap(), application.options.reporter)));
ps.append("\n");
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 789bb19..dc18cfe 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -19,8 +19,8 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
import java.util.Objects;
@@ -237,7 +237,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return "ThrowExceptionCode";
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index cac6f7a..661cefb 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -22,9 +22,9 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.google.common.collect.ImmutableList;
import java.nio.ShortBuffer;
@@ -266,7 +266,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return "ThrowNullCode";
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
index c9c8e34..abb1fbf 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
public abstract class IncompleteHorizontalClassMergerCode extends Code {
@@ -80,7 +80,7 @@
public abstract String toString();
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return toString();
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index 2e6cc06..6a030d7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -35,11 +35,11 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.CfVersionUtils;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -311,7 +311,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
throw new Unreachable();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 30c3b67..2a543a8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueNull;
import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
@@ -29,6 +30,7 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Value;
@@ -37,6 +39,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
import java.util.IdentityHashMap;
+import java.util.List;
import java.util.Map;
public class StaticFieldValueAnalysis extends FieldValueAnalysis {
@@ -210,7 +213,7 @@
if (value.isPhi()) {
return null;
}
- if (value.definition.isNewArrayEmpty()) {
+ if (value.definition.isNewArrayEmptyOrInvokeNewArray()) {
return computeSingleEnumFieldValueForValuesArray(value);
}
if (value.definition.isNewInstance()) {
@@ -220,7 +223,7 @@
}
private SingleFieldValue computeSingleEnumFieldValueForValuesArray(Value value) {
- if (!value.definition.isNewArrayEmpty()) {
+ if (!value.definition.isNewArrayEmptyOrInvokeNewArray()) {
return null;
}
AbstractValue valuesValue = computedValues.get(value);
@@ -241,26 +244,38 @@
}
private SingleFieldValue internalComputeSingleEnumFieldValueForValuesArray(Value value) {
- assert value.isDefinedByInstructionSatisfying(Instruction::isNewArrayEmpty);
-
NewArrayEmpty newArrayEmpty = value.definition.asNewArrayEmpty();
- if (newArrayEmpty.type.toBaseType(appView.dexItemFactory()) != context.getHolder().type) {
+ InvokeNewArray invokeNewArray = value.definition.asInvokeNewArray();
+ assert newArrayEmpty != null || invokeNewArray != null;
+
+ DexType arrayType = newArrayEmpty != null ? newArrayEmpty.type : invokeNewArray.getArrayType();
+ if (arrayType.toBaseType(appView.dexItemFactory()) != context.getHolder().type) {
return null;
}
if (value.hasDebugUsers() || value.hasPhiUsers()) {
return null;
}
- if (!newArrayEmpty.size().isConstNumber()) {
- return null;
- }
- int valuesSize = newArrayEmpty.size().getConstInstruction().asConstNumber().getIntValue();
- if (valuesSize == 0) {
- // No need to compute the state of an empty array.
+ int valuesSize = newArrayEmpty != null ? newArrayEmpty.sizeIfConst() : invokeNewArray.size();
+ if (valuesSize < 1) {
+ // Array is empty or non-const size.
return null;
}
ObjectState[] valuesState = new ObjectState[valuesSize];
+
+ if (invokeNewArray != null) {
+ // Populate array values from filled-new-array values.
+ List<Value> inValues = invokeNewArray.inValues();
+ for (int i = 0; i < valuesSize; ++i) {
+ if (!updateEnumValueState(valuesState, i, inValues.get(i))) {
+ return null;
+ }
+ }
+ }
+
+ // Populate / update array values from aput-object instructions, and find the static-put
+ // instruction.
DexEncodedField valuesField = null;
for (Instruction user : value.aliasedUsers()) {
switch (user.opcode()) {
@@ -276,18 +291,9 @@
if (index < 0 || index >= valuesSize) {
return null;
}
- ObjectState objectState = computeEnumInstanceObjectState(arrayPut.value());
- if (objectState == null || objectState.isEmpty()) {
- // We need the state of all fields for the analysis to be valuable.
+ if (!updateEnumValueState(valuesState, index, arrayPut.value())) {
return null;
}
- if (!valuesArrayIndexMatchesOrdinal(index, objectState)) {
- return null;
- }
- if (valuesState[index] != null) {
- return null;
- }
- valuesState[index] = objectState;
break;
case ASSUME:
@@ -328,24 +334,34 @@
.createSingleFieldValue(valuesField.getReference(), new EnumValuesObjectState(valuesState));
}
- private ObjectState computeEnumInstanceObjectState(Value value) {
+ private boolean updateEnumValueState(ObjectState[] valuesState, int index, Value value) {
Value root = value.getAliasedValue();
if (root.isPhi()) {
- return ObjectState.empty();
+ return false;
}
Instruction definition = root.getDefinition();
- if (definition.isNewInstance()) {
- return computeObjectState(definition.outValue());
- }
if (definition.isStaticGet()) {
// Enums with many instance rely on staticGets to set the $VALUES data instead of directly
// keeping the values in registers, due to the max capacity of the redundant field load
// elimination. The capacity has already been increased, so that this case is extremely
// uncommon (very large enums).
// TODO(b/169050248): We could consider analysing these to answer the object state here.
- return ObjectState.empty();
+ return false;
}
- return ObjectState.empty();
+ ObjectState objectState =
+ definition.isNewInstance() ? computeObjectState(definition.outValue()) : null;
+ if (objectState == null || objectState.isEmpty()) {
+ // We need the state of all fields for the analysis to be valuable.
+ return false;
+ }
+ if (!valuesArrayIndexMatchesOrdinal(index, objectState)) {
+ return false;
+ }
+ if (valuesState[index] != null) {
+ return false;
+ }
+ valuesState[index] = objectState;
+ return true;
}
private boolean valuesArrayIndexMatchesOrdinal(int ordinal, ObjectState objectState) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
index 74a3fb5..b4b2359 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
@@ -33,6 +33,7 @@
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewInstance;
@@ -46,6 +47,7 @@
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -316,17 +318,37 @@
Value sizeValue =
instructionIterator.insertConstIntInstruction(code, appView.options(), objects.size());
Value newObjectsValue = code.createValue(objectArrayType);
- instructionIterator.add(
- new NewArrayEmpty(newObjectsValue, sizeValue, appView.dexItemFactory().objectArrayType));
// Populate the `objects` array.
- for (int i = 0; i < objects.size(); i++) {
- Value indexValue = instructionIterator.insertConstIntInstruction(code, appView.options(), i);
- Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
- instructionIterator.add(materializingInstruction);
+ var rewriteOptions = appView.options().rewriteArrayOptions();
+ if (rewriteOptions.canUseFilledNewArrayOfObjects()
+ && objects.size() < rewriteOptions.maxRangeInputs) {
+ List<Value> arrayValues = new ArrayList<>(objects.size());
+ for (int i = 0; i < objects.size(); i++) {
+ Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
+ instructionIterator.add(materializingInstruction);
+ arrayValues.add(materializingInstruction.outValue());
+ }
instructionIterator.add(
- new ArrayPut(
- MemberType.OBJECT, newObjectsValue, indexValue, materializingInstruction.outValue()));
+ new InvokeNewArray(
+ appView.dexItemFactory().objectArrayType, newObjectsValue, arrayValues));
+ } else {
+ instructionIterator.add(
+ new NewArrayEmpty(newObjectsValue, sizeValue, appView.dexItemFactory().objectArrayType));
+
+ // Populate the `objects` array.
+ for (int i = 0; i < objects.size(); i++) {
+ Value indexValue =
+ instructionIterator.insertConstIntInstruction(code, appView.options(), i);
+ Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
+ instructionIterator.add(materializingInstruction);
+ instructionIterator.add(
+ new ArrayPut(
+ MemberType.OBJECT,
+ newObjectsValue,
+ indexValue,
+ materializingInstruction.outValue()));
+ }
}
// Pass the newly created `objects` array to RawMessageInfo.<init>(...) or
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
index fbe3ff5..c25c456 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/RawMessageInfoDecoder.java
@@ -31,6 +31,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.StaticGet;
@@ -302,18 +303,30 @@
*/
private static ThrowingIterator<Value, InvalidRawMessageInfoException> createObjectIterator(
Value objectsValue) throws InvalidRawMessageInfoException {
- if (objectsValue.isPhi() || !objectsValue.definition.isNewArrayEmpty()) {
+ if (objectsValue.isPhi()) {
throw new InvalidRawMessageInfoException();
}
NewArrayEmpty newArrayEmpty = objectsValue.definition.asNewArrayEmpty();
- int expectedArraySize = objectsValue.uniqueUsers().size() - 1;
+ InvokeNewArray invokeNewArray = objectsValue.definition.asInvokeNewArray();
- // Verify that the size is correct.
+ if (newArrayEmpty == null && invokeNewArray == null) {
+ throw new InvalidRawMessageInfoException();
+ }
+ // Verify that the array is used in only one spot.
+ if (invokeNewArray != null) {
+ if (objectsValue.uniqueUsers().size() != 1) {
+ throw new InvalidRawMessageInfoException();
+ }
+ return ThrowingIterator.fromIterator(invokeNewArray.inValues().iterator());
+ }
+
Value sizeValue = newArrayEmpty.size().getAliasedValue();
- if (sizeValue.isPhi()
- || !sizeValue.definition.isConstNumber()
- || sizeValue.definition.asConstNumber().getIntValue() != expectedArraySize) {
+ if (sizeValue.isPhi() || !sizeValue.definition.isConstNumber()) {
+ throw new InvalidRawMessageInfoException();
+ }
+ int arraySize = sizeValue.definition.asConstNumber().getIntValue();
+ if (arraySize != objectsValue.uniqueUsers().size() - 1) {
throw new InvalidRawMessageInfoException();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java
index e06cdbee..99f92eb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeUtils.java
@@ -73,20 +73,25 @@
* <p>Use with caution!
*/
public static void removeArrayAndTransitiveInputsIfNotUsed(IRCode code, Instruction definition) {
- Deque<InstructionOrPhi> worklist = new ArrayDeque<>();
if (definition.isConstNumber()) {
// No need to explicitly remove `null`, it will be removed by ordinary dead code elimination
// anyway.
assert definition.asConstNumber().isZero();
return;
}
-
- if (definition.isNewArrayEmpty()) {
- Value arrayValue = definition.outValue();
- if (arrayValue.hasPhiUsers() || arrayValue.hasDebugUsers()) {
- return;
- }
-
+ Value arrayValue = definition.outValue();
+ if (arrayValue.hasPhiUsers() || arrayValue.hasDebugUsers()) {
+ return;
+ }
+ if (!definition.isNewArrayEmptyOrInvokeNewArray()) {
+ assert false;
+ return;
+ }
+ Deque<InstructionOrPhi> worklist = new ArrayDeque<>();
+ InvokeNewArray invokeNewArray = definition.asInvokeNewArray();
+ if (invokeNewArray != null) {
+ worklist.add(definition);
+ } else if (definition.isNewArrayEmpty()) {
for (Instruction user : arrayValue.uniqueUsers()) {
// If we encounter an Assume instruction here, we also need to consider indirect users.
assert !user.isAssume();
@@ -95,11 +100,10 @@
}
worklist.add(user);
}
- internalRemoveInstructionAndTransitiveInputsIfNotUsed(code, worklist);
- return;
+ } else {
+ assert false;
}
-
- assert false;
+ internalRemoveInstructionAndTransitiveInputsIfNotUsed(code, worklist);
}
/**
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 c99ee11..8892da0 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
@@ -1038,6 +1038,10 @@
return false;
}
+ public boolean isNewArrayEmptyOrInvokeNewArray() {
+ return isNewArrayEmpty() || isInvokeNewArray();
+ }
+
public NewArrayEmpty asNewArrayEmpty() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index a2e815f..f0715b5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -221,4 +221,9 @@
void internalRegisterUse(UseRegistry<?> registry, DexClassAndMethod context) {
registry.registerTypeReference(type);
}
+
+ // Returns the number of elements in the array.
+ public int size() {
+ return inValues.size();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index c6d527f..a829247 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -49,10 +49,6 @@
return super.toString() + " " + type.toString();
}
- public Value dest() {
- return outValue;
- }
-
public Value size() {
return inValues.get(0);
}
@@ -60,7 +56,7 @@
@Override
public void buildDex(DexBuilder builder) {
int size = builder.allocatedRegister(size(), getNumber());
- int dest = builder.allocatedRegister(dest(), getNumber());
+ int dest = builder.allocatedRegister(outValue, getNumber());
builder.add(this, new DexNewArray(dest, size, type));
}
@@ -171,4 +167,10 @@
void internalRegisterUse(UseRegistry<?> registry, DexClassAndMethod context) {
registry.registerTypeReference(type);
}
+
+ // Returns the size of the array if it is known, -1 otherwise.
+ public int sizeIfConst() {
+ Value size = size();
+ return size.isConstNumber() ? size.getConstInstruction().asConstNumber().getIntValue() : -1;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 178255b..40f9d67 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -170,7 +170,9 @@
private DexMethod ensureApiGenericConversion(
DexMethod conversion, DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer) {
- assert !appView.options().isDesugaredLibraryCompilation();
+ if (appView.appInfoForDesugaring().resolveMethod(conversion, false).isSingleResolution()) {
+ return conversion;
+ }
ClasspathMethod classpathMethod =
appView
.getSyntheticItems()
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 7a669c2..ae3214b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -14,6 +14,8 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -29,12 +31,14 @@
private final Set<DexString> descriptorDontRewritePrefix;
private final Map<DexString, Map<DexString, DexString>> descriptorDifferentPrefix;
private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
+ private final boolean jdk11Legacy;
public HumanToMachinePrefixConverter(
AppInfoWithClassHierarchy appInfo,
MachineRewritingFlags.Builder builder,
String synthesizedPrefix,
boolean libraryCompilation,
+ String identifier,
HumanRewritingFlags rewritingFlags) {
this.appInfo = appInfo;
this.builder = builder;
@@ -45,6 +49,7 @@
this.descriptorMaintainPrefix = convertPrefixSet(rewritingFlags.getMaintainPrefix());
this.descriptorDifferentPrefix =
convertRewriteDifferentPrefix(rewritingFlags.getRewriteDerivedPrefix());
+ this.jdk11Legacy = identifier.startsWith("com.tools.android:desugar_jdk_libs:1.2.");
}
public void convertPrefixFlags(
@@ -63,12 +68,27 @@
}
private void warnIfUnusedPrefix(BiConsumer<String, Set<DexString>> warnConsumer) {
- Set<DexString> prefixes = Sets.newIdentityHashSet();
- prefixes.addAll(descriptorPrefix.keySet());
- prefixes.addAll(descriptorMaintainPrefix);
- prefixes.addAll(descriptorDifferentPrefix.keySet());
- prefixes.removeAll(usedPrefix);
- warnConsumer.accept("The following prefixes do not match any type: ", prefixes);
+ Set<DexString> unused = Sets.newIdentityHashSet();
+ unused.addAll(descriptorPrefix.keySet());
+ unused.addAll(descriptorMaintainPrefix);
+ unused.addAll(descriptorDifferentPrefix.keySet());
+ unused.removeAll(usedPrefix);
+ if (jdk11Legacy) {
+ // We have to allow duplicate because of the jdk11 legacy configuration, since there is no
+ // api_greater_or_equal in legacy, we're bound to have duplicates.
+ // If we have x.y. -> w.z and x. -> w., then if one is used the other is used.
+ List<DexString> duplicates = new ArrayList<>();
+ for (DexString prefix : unused) {
+ descriptorPrefix.forEach(
+ (k, v) -> {
+ if (!unused.contains(k) && (k.startsWith(prefix) || prefix.startsWith(k))) {
+ duplicates.add(prefix);
+ }
+ });
+ }
+ duplicates.forEach(unused::remove);
+ }
+ warnConsumer.accept("The following prefixes do not match any type: ", unused);
}
public DexType convertJavaNameToDesugaredLibrary(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index 2773de6..48f3aaa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -57,12 +57,13 @@
MachineTopLevelFlags machineTopLevelFlags = convertTopLevelFlags(humanSpec.getTopLevelFlags());
String synthesizedPrefix = machineTopLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
+ String identifier = machineTopLevelFlags.getIdentifier();
Map<ApiLevelRange, MachineRewritingFlags> commonFlags =
- convertRewritingFlagMap(humanSpec.getCommonFlags(), synthesizedPrefix, true);
+ convertRewritingFlagMap(humanSpec.getCommonFlags(), synthesizedPrefix, true, identifier);
Map<ApiLevelRange, MachineRewritingFlags> programFlags =
- convertRewritingFlagMap(humanSpec.getProgramFlags(), synthesizedPrefix, false);
+ convertRewritingFlagMap(humanSpec.getProgramFlags(), synthesizedPrefix, false, identifier);
Map<ApiLevelRange, MachineRewritingFlags> libraryFlags =
- convertRewritingFlagMap(humanSpec.getLibraryFlags(), synthesizedPrefix, true);
+ convertRewritingFlagMap(humanSpec.getLibraryFlags(), synthesizedPrefix, true, identifier);
MultiAPILevelMachineDesugaredLibrarySpecification machineSpec =
new MultiAPILevelMachineDesugaredLibrarySpecification(
@@ -74,13 +75,15 @@
private Map<ApiLevelRange, MachineRewritingFlags> convertRewritingFlagMap(
Map<ApiLevelRange, HumanRewritingFlags> libFlags,
String synthesizedPrefix,
- boolean interpretAsLibraryCompilation) {
+ boolean interpretAsLibraryCompilation,
+ String identifier) {
Map<ApiLevelRange, MachineRewritingFlags> map = new HashMap<>();
libFlags.forEach(
(range, flags) ->
map.put(
range,
- convertRewritingFlags(flags, synthesizedPrefix, interpretAsLibraryCompilation)));
+ convertRewritingFlags(
+ flags, synthesizedPrefix, interpretAsLibraryCompilation, identifier)));
return map;
}
@@ -99,7 +102,8 @@
convertRewritingFlags(
humanSpec.getRewritingFlags(),
humanSpec.getSynthesizedLibraryClassesPackagePrefix(),
- humanSpec.isLibraryCompilation());
+ humanSpec.isLibraryCompilation(),
+ humanSpec.getIdentifier());
MachineTopLevelFlags topLevelFlags = convertTopLevelFlags(humanSpec.getTopLevelFlags());
timing.end();
return new MachineDesugaredLibrarySpecification(
@@ -117,7 +121,10 @@
}
private MachineRewritingFlags convertRewritingFlags(
- HumanRewritingFlags rewritingFlags, String synthesizedPrefix, boolean libraryCompilation) {
+ HumanRewritingFlags rewritingFlags,
+ String synthesizedPrefix,
+ boolean libraryCompilation,
+ String identifier) {
timing.begin("convert rewriting flags");
MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
DesugaredLibraryAmender.run(
@@ -135,7 +142,7 @@
new HumanToMachineEmulatedInterfaceConverter(appInfo)
.convertEmulatedInterfaces(rewritingFlags, appInfo, builder, this::warnMissingReferences);
new HumanToMachinePrefixConverter(
- appInfo, builder, synthesizedPrefix, libraryCompilation, rewritingFlags)
+ appInfo, builder, synthesizedPrefix, libraryCompilation, identifier, rewritingFlags)
.convertPrefixFlags(rewritingFlags, this::warnMissingDexString);
new HumanToMachineWrapperConverter(appInfo)
.convertWrappers(rewritingFlags, builder, this::warnMissingReferences);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
index c6ea5b0..2acd508 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
@@ -27,7 +27,7 @@
} else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.R)) {
levelType = app.dexItemFactory.createType("Ljava/util/concurrent/Flow;");
} else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.N)) {
- levelType = app.dexItemFactory.createType("Ljava/util/function/Supplier;");
+ levelType = app.dexItemFactory.createType("Ljava/util/StringJoiner;");
} else if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.T)) {
levelType = app.dexItemFactory.createType("Ljava/lang/invoke/VarHandle;");
} else {
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 6314197..1d4e435 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
@@ -16,7 +16,6 @@
import com.android.tools.r8.algorithms.scc.SCC;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
-import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AccessControl;
@@ -55,7 +54,6 @@
import com.android.tools.r8.ir.code.CatchHandlers.CatchHandler;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DebugLocalWrite;
@@ -84,6 +82,7 @@
import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.LinearFlowInstructionListIterator;
import com.android.tools.r8.ir.code.Move;
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewArrayFilledData;
@@ -138,6 +137,7 @@
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
@@ -162,7 +162,6 @@
FALSE
}
- private static final int MAX_FILL_ARRAY_SIZE = 8 * Constants.KILOBYTE;
// This constant was determined by experimentation.
private static final int STOP_SHARED_CONSTANT_THRESHOLD = 50;
@@ -2100,16 +2099,21 @@
}
}
- private short[] computeArrayFilledData(ConstInstruction[] values, int size, int elementSize) {
- if (values == null) {
- return null;
+ private short[] computeArrayFilledData(Value[] values, int size, int elementSize) {
+ for (Value v : values) {
+ if (!v.isConstant()) {
+ return null;
+ }
}
if (elementSize == 1) {
short[] result = new short[(size + 1) / 2];
for (int i = 0; i < size; i += 2) {
- short value = (short) (values[i].asConstNumber().getIntValue() & 0xFF);
+ short value =
+ (short) (values[i].getConstInstruction().asConstNumber().getIntValue() & 0xFF);
if (i + 1 < size) {
- value |= (short) ((values[i + 1].asConstNumber().getIntValue() & 0xFF) << 8);
+ value |=
+ (short)
+ ((values[i + 1].getConstInstruction().asConstNumber().getIntValue() & 0xFF) << 8);
}
result[i / 2] = value;
}
@@ -2119,7 +2123,7 @@
int shortsPerConstant = elementSize / 2;
short[] result = new short[size * shortsPerConstant];
for (int i = 0; i < size; i++) {
- long value = values[i].asConstNumber().getRawValue();
+ long value = values[i].getConstInstruction().asConstNumber().getRawValue();
for (int part = 0; part < shortsPerConstant; part++) {
result[i * shortsPerConstant + part] = (short) ((value >> (16 * part)) & 0xFFFFL);
}
@@ -2127,40 +2131,45 @@
return result;
}
- private ConstInstruction[] computeConstantArrayValues(
- NewArrayEmpty newArray, BasicBlock block, int size) {
- if (size > MAX_FILL_ARRAY_SIZE) {
- return null;
- }
- ConstInstruction[] values = new ConstInstruction[size];
+ private Value[] computeArrayValues(LinearFlowInstructionListIterator it, int size) {
+ NewArrayEmpty newArrayEmpty = it.next().asNewArrayEmpty();
+ assert newArrayEmpty != null;
+ Value arrayValue = newArrayEmpty.outValue();
+
+ // aput-object allows any object for arrays of interfaces, but new-filled-array fails to verify
+ // if types require a cast.
+ // TODO(b/246971330): Check if adding a checked-cast would have the same observable result. E.g.
+ // if aput-object throws a ClassCastException if given an object that does not implement the
+ // desired interface, then we could add check-cast instructions for arguments we're not sure
+ // about.
+ DexType elementType = newArrayEmpty.type.toDimensionMinusOneType(dexItemFactory);
+ boolean needsTypeCheck =
+ !elementType.isPrimitiveType() && elementType != dexItemFactory.objectType;
+
+ Value[] values = new Value[size];
int remaining = size;
- Set<Instruction> users = newArray.outValue().uniqueUsers();
- Set<BasicBlock> visitedBlocks = Sets.newIdentityHashSet();
- // We allow the array instantiations to cross block boundaries as long as it hasn't encountered
- // an instruction instance that can throw an exception.
- InstructionIterator it = block.iterator();
- it.nextUntil(i -> i == newArray);
- do {
- visitedBlocks.add(block);
+ Set<Instruction> users = newArrayEmpty.outValue().uniqueUsers();
while (it.hasNext()) {
Instruction instruction = it.next();
- // If we encounter an instruction that can throw an exception we need to bail out of the
- // optimization so that we do not transform half-initialized arrays into fully initialized
- // arrays on exceptional edges. If the block has no handlers it is not observable so
- // we perform the rewriting.
- if (block.hasCatchHandlers() && instruction.instructionInstanceCanThrow()) {
+ // If we encounter an instruction that can throw an exception we need to bail out of the
+ // optimization so that we do not transform half-initialized arrays into fully initialized
+ // arrays on exceptional edges. If the block has no handlers it is not observable so
+ // we perform the rewriting.
+ // TODO(b/246971330): Allow simplification when all users of the array are in the same
+ // try/catch.
+ if (instruction.getBlock().hasCatchHandlers() && instruction.instructionInstanceCanThrow()) {
return null;
}
if (!users.contains(instruction)) {
continue;
}
- // If the initialization sequence is broken by another use we cannot use a
- // fill-array-data instruction.
- if (!instruction.isArrayPut()) {
+ ArrayPut arrayPut = instruction.asArrayPut();
+ // If the initialization sequence is broken by another use we cannot use a fill-array-data
+ // instruction.
+ if (arrayPut == null || arrayPut.array() != arrayValue) {
return null;
}
- ArrayPut arrayPut = instruction.asArrayPut();
- if (!(arrayPut.value().isConstant() && arrayPut.index().isConstNumber())) {
+ if (!arrayPut.index().isConstNumber()) {
return null;
}
int index = arrayPut.index().getConstInstruction().asConstNumber().getIntValue();
@@ -2170,40 +2179,38 @@
if (values[index] != null) {
return null;
}
- ConstInstruction value = arrayPut.value().getConstInstruction();
+ Value value = arrayPut.value();
+ if (needsTypeCheck && !value.isAlwaysNull(appView)) {
+ DexType valueDexType = value.getType().asReferenceType().toDexType(dexItemFactory);
+ if (elementType.isArrayType()) {
+ if (elementType != valueDexType) {
+ return null;
+ }
+ } else if (valueDexType.isArrayType()) {
+ // isSubtype asserts for this case.
+ return null;
+ } else if (valueDexType.isNullValueType()) {
+ // Assume instructions can cause value.isAlwaysNull() == false while the DexType is
+ // null.
+ // TODO(b/246971330): Figure out how to write a test in SimplifyArrayConstructionTest
+ // that hits this case.
+ } else {
+ // TODO(b/246971330): When in d8 mode, we might still be able to see if this is true for
+ // library types (which this helper does not do).
+ if (appView.isSubtype(valueDexType, elementType).isPossiblyFalse()) {
+ return null;
+ }
+ }
+ }
values[index] = value;
--remaining;
if (remaining == 0) {
return values;
}
}
- BasicBlock nextBlock = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
- block = nextBlock != null && !visitedBlocks.contains(nextBlock) ? nextBlock : null;
- it = block != null ? block.iterator() : null;
- } while (it != null);
return null;
}
- private boolean allowNewFilledArrayConstruction(Instruction instruction) {
- if (!(instruction instanceof NewArrayEmpty)) {
- return false;
- }
- NewArrayEmpty newArray = instruction.asNewArrayEmpty();
- if (!newArray.size().isConstant()) {
- return false;
- }
- assert newArray.size().isConstNumber();
- int size = newArray.size().getConstInstruction().asConstNumber().getIntValue();
- if (size < 1) {
- return false;
- }
- if (newArray.type.isPrimitiveArrayType()) {
- return true;
- }
- return newArray.type == dexItemFactory.stringArrayType
- && options.canUseFilledNewArrayOfObjects();
- }
-
/**
* Replace new-array followed by stores of constants to all entries with new-array
* and fill-array-data / filled-new-array.
@@ -2212,6 +2219,11 @@
if (options.isGeneratingClassFiles()) {
return;
}
+ InternalOptions.RewriteArrayOptions rewriteOptions = options.rewriteArrayOptions();
+ boolean canUseForStrings = rewriteOptions.canUseFilledNewArrayOfStrings();
+ boolean canUseForObjects = rewriteOptions.canUseFilledNewArrayOfObjects();
+ boolean canUseForArrays = rewriteOptions.canUseFilledNewArrayOfArrays();
+
for (BasicBlock block : code.blocks) {
// Map from the array value to the number of array put instruction to remove for that value.
Map<Value, Instruction> instructionToInsertForArray = new HashMap<>();
@@ -2220,31 +2232,56 @@
InstructionListIterator it = block.listIterator(code);
while (it.hasNext()) {
Instruction instruction = it.next();
- if (instruction.getLocalInfo() != null || !allowNewFilledArrayConstruction(instruction)) {
+ NewArrayEmpty newArrayEmpty = instruction.asNewArrayEmpty();
+ if (newArrayEmpty == null || !newArrayEmpty.size().isConstant()) {
continue;
}
- NewArrayEmpty newArray = instruction.asNewArrayEmpty();
- int size = newArray.size().getConstInstruction().asConstNumber().getIntValue();
- ConstInstruction[] values = computeConstantArrayValues(newArray, block, size);
+ if (instruction.getLocalInfo() != null) {
+ continue;
+ }
+ int size = newArrayEmpty.size().getConstInstruction().asConstNumber().getIntValue();
+ if (size < 1 || size > rewriteOptions.maxFillArrayDataInputs) {
+ continue;
+ }
+ DexType arrayType = newArrayEmpty.type;
+ if (!arrayType.isPrimitiveArrayType()) {
+ if (arrayType == dexItemFactory.stringArrayType) {
+ if (!canUseForStrings) {
+ continue;
+ }
+ } else if (!canUseForObjects) {
+ continue;
+ } else if (!canUseForArrays && arrayType.getNumberOfLeadingSquareBrackets() > 1) {
+ continue;
+ }
+ }
+
+ Value[] values =
+ computeArrayValues(
+ new LinearFlowInstructionListIterator(code, block, it.previousIndex()), size);
if (values == null) {
continue;
}
- if (newArray.type == dexItemFactory.stringArrayType) {
+ // filled-new-array is implemented only for int[] and Object[].
+ // For int[], using filled-new-array is usually smaller than filled-array-data.
+ // filled-new-array supports up to 5 registers before it's filled-new-array/range.
+ if (!arrayType.isPrimitiveArrayType()
+ || (arrayType == dexItemFactory.intArrayType && size <= 5)) {
// Don't replace with filled-new-array if it requires more than 200 consecutive registers.
- if (size > 200) {
+ if (size > rewriteOptions.maxRangeInputs) {
continue;
}
- List<Value> stringValues = new ArrayList<>(size);
- for (ConstInstruction value : values) {
- stringValues.add(value.outValue());
+ // block.hasCatchHandlers() is fine here since new-array-filled replaces new-array-empty
+ // and computeArrayValues already checks that no throwing instructions exist between the
+ // original new-array-empty and the final aput-object (where the new-array-filled will be
+ // positioned).
+ Value invokeValue =
+ code.createValue(newArrayEmpty.getOutType(), newArrayEmpty.getLocalInfo());
+ InvokeNewArray invoke = new InvokeNewArray(arrayType, invokeValue, Arrays.asList(values));
+ for (Value value : newArrayEmpty.inValues()) {
+ value.removeUser(newArrayEmpty);
}
- Value invokeValue = code.createValue(newArray.getOutType(), newArray.getLocalInfo());
- InvokeNewArray invoke =
- new InvokeNewArray(dexItemFactory.stringArrayType, invokeValue, stringValues);
- for (Value value : newArray.inValues()) {
- value.removeUser(newArray);
- }
- newArray.outValue().replaceUsers(invokeValue);
+ newArrayEmpty.outValue().replaceUsers(invokeValue);
it.removeOrReplaceByDebugLocalRead();
instructionToInsertForArray.put(invokeValue, invoke);
storesToRemoveForArray.put(invokeValue, size);
@@ -2254,26 +2291,33 @@
if (size == 1) {
continue;
}
- int elementSize = newArray.type.elementSizeForPrimitiveArrayType();
+ // TODO(b/246971330): Allow simplification when all users of the array are in the same
+ // try/catch.
+ if (block.hasCatchHandlers()) {
+ // NewArrayFilledData can throw, so creating one as done below would add a second
+ // throwing instruction to the same block (the first one being NewArrayEmpty).
+ continue;
+ }
+ int elementSize = arrayType.elementSizeForPrimitiveArrayType();
short[] contents = computeArrayFilledData(values, size, elementSize);
if (contents == null) {
continue;
}
- if (block.hasCatchHandlers()) {
- continue;
- }
- int arraySize = newArray.size().getConstInstruction().asConstNumber().getIntValue();
+ int arraySize = newArrayEmpty.size().getConstInstruction().asConstNumber().getIntValue();
+ // fill-array-data requires the new-array-empty instruction to remain, as it does not
+ // itself create an array.
NewArrayFilledData fillArray =
- new NewArrayFilledData(newArray.outValue(), elementSize, arraySize, contents);
- fillArray.setPosition(newArray.getPosition());
+ new NewArrayFilledData(newArrayEmpty.outValue(), elementSize, arraySize, contents);
+ fillArray.setPosition(newArrayEmpty.getPosition());
it.add(fillArray);
- storesToRemoveForArray.put(newArray.outValue(), size);
+ storesToRemoveForArray.put(newArrayEmpty.outValue(), size);
}
}
// Second pass: remove all the array put instructions for the array for which we have
// inserted a fill array data instruction instead.
if (!storesToRemoveForArray.isEmpty()) {
Set<BasicBlock> visitedBlocks = Sets.newIdentityHashSet();
+ int numInstructionsInserted = 0;
do {
visitedBlocks.add(block);
it = block.listIterator(code);
@@ -2295,6 +2339,7 @@
// last removed put at which point we are now adding the construction.
construction.setPosition(instruction.getPosition());
it.add(construction);
+ numInstructionsInserted += 1;
}
}
}
@@ -2303,6 +2348,7 @@
BasicBlock nextBlock = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
block = nextBlock != null && !visitedBlocks.contains(nextBlock) ? nextBlock : null;
} while (block != null);
+ assert numInstructionsInserted == instructionToInsertForArray.size();
}
}
assert code.isConsistentSSA(appView);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
index 2cab3fb..4a99fb4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/OutlinerImpl.java
@@ -66,12 +66,12 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.outliner.OutlineCollection;
import com.android.tools.r8.ir.optimize.outliner.Outliner;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.android.tools.r8.utils.ThreadUtils;
@@ -1830,7 +1830,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return null;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index a649af6..6fb553c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -18,6 +18,7 @@
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_CUSTOM;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_DIRECT;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_INTERFACE;
+import static com.android.tools.r8.ir.code.Opcodes.INVOKE_NEW_ARRAY;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_STATIC;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_SUPER;
import static com.android.tools.r8.ir.code.Opcodes.INVOKE_VIRTUAL;
@@ -68,6 +69,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeCustom;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.MemberType;
@@ -1060,6 +1062,10 @@
instruction.asInstancePut(), code, context, enumClass, enumValue);
case INVOKE_DIRECT:
case INVOKE_INTERFACE:
+ return analyzeInvokeUser(instruction.asInvokeMethod(), code, context, enumClass, enumValue);
+ case INVOKE_NEW_ARRAY:
+ return analyzeInvokeNewArrayUser(
+ instruction.asInvokeNewArray(), code, context, enumClass, enumValue);
case INVOKE_STATIC:
case INVOKE_SUPER:
case INVOKE_VIRTUAL:
@@ -1130,6 +1136,40 @@
return Reason.INVALID_ARRAY_PUT;
}
+ private Reason analyzeInvokeNewArrayUser(
+ InvokeNewArray invokeNewArray,
+ IRCode code,
+ ProgramMethod context,
+ DexProgramClass enumClass,
+ Value enumValue) {
+ // MyEnum[] array = new MyEnum[] { MyEnum.A }; is valid.
+ // We need to prove that the value to put in and the array have correct types.
+ TypeElement arrayType = invokeNewArray.getOutType();
+ assert arrayType.isArrayType();
+
+ ClassTypeElement arrayBaseType = arrayType.asArrayType().getBaseType().asClassType();
+ if (arrayBaseType == null) {
+ assert false;
+ return Reason.INVALID_INVOKE_NEW_ARRAY;
+ }
+ if (arrayBaseType.getClassType() != enumClass.type) {
+ return Reason.INVALID_INVOKE_NEW_ARRAY;
+ }
+
+ for (Value value : invokeNewArray.inValues()) {
+ TypeElement valueBaseType = value.getType();
+ if (valueBaseType.isArrayType()) {
+ assert valueBaseType.asArrayType().getBaseType().isClassType();
+ assert valueBaseType.asArrayType().getNesting() == arrayType.asArrayType().getNesting() - 1;
+ valueBaseType = valueBaseType.asArrayType().getBaseType();
+ }
+ if (!arrayBaseType.equalUpToNullability(valueBaseType)) {
+ return Reason.INVALID_INVOKE_NEW_ARRAY;
+ }
+ }
+ return Reason.ELIGIBLE;
+ }
+
private Reason analyzeCheckCastUser(
CheckCast checkCast,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
index 6e187ae..4e7801c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
@@ -19,9 +19,9 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.IteratorUtils;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
/**
* A special code object used by enum unboxing that supplies IR from an existing method
@@ -128,7 +128,7 @@
}
@Override
- public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return toString();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
index 3e17a0a..7cb0290 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/eligibility/Reason.java
@@ -32,6 +32,8 @@
new StringReason("IMPLICIT_UP_CAST_IN_RETURN");
public static final Reason INVALID_FIELD_PUT = new StringReason("INVALID_FIELD_PUT");
public static final Reason INVALID_ARRAY_PUT = new StringReason("INVALID_ARRAY_PUT");
+ public static final Reason INVALID_INVOKE_NEW_ARRAY =
+ new StringReason("INVALID_INVOKE_NEW_ARRAY");
public static final Reason TYPE_MISMATCH_FIELD_PUT = new StringReason("TYPE_MISMATCH_FIELD_PUT");
public static final Reason INVALID_IF_TYPES = new StringReason("INVALID_IF_TYPES");
public static final Reason ASSIGNMENT_OUTSIDE_INIT = new StringReason("ASSIGNMENT_OUTSIDE_INIT");
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index 8c28b9e..ad0b54c 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -21,8 +21,8 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.ThrowingMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.RetracerForCodePrinting;
import java.util.function.Consumer;
public abstract class AbstractSynthesizedCode extends Code {
@@ -73,7 +73,7 @@
@Override
public final String toString() {
- return toString(null, null);
+ return toString(null, RetracerForCodePrinting.empty());
}
@Override
@@ -101,7 +101,7 @@
}
@Override
- public final String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ public final String toString(DexEncodedMethod method, RetracerForCodePrinting retracer) {
return this.getClass().getSimpleName();
}
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
index 3e4078b..6e14907 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.NewArrayEmpty;
@@ -424,12 +425,16 @@
// Perform a conservative evaluation of an array content of dex type values from its construction
// until its use at a given instruction.
- private static DexType[] evaluateTypeArrayContentFromConstructionToUse(
- NewArrayEmpty newArray,
- List<CheckCast> aliases,
- int size,
- Instruction user,
- DexItemFactory factory) {
+ private static DexTypeList evaluateTypeArrayContentFromConstructionToUse(
+ NewArrayEmpty newArray, List<CheckCast> aliases, Instruction user, DexItemFactory factory) {
+ int size = newArray.sizeIfConst();
+ if (size < 0) {
+ return null;
+ } else if (size == 0) {
+ // TODO: We should likely still scan to ensure no ArrayPut instructions exist.
+ return DexTypeList.empty();
+ }
+
DexType[] values = new DexType[size];
int remaining = size;
Set<Instruction> users = Sets.newIdentityHashSet();
@@ -453,7 +458,7 @@
if (instruction == user) {
// Return the array content if all elements are known when hitting the user for which
// the content was requested.
- return remaining == 0 ? values : null;
+ return remaining == 0 ? new DexTypeList(values) : null;
}
// Any other kinds of use besides array-put mean that the array escapes and its content
// could be altered.
@@ -498,6 +503,21 @@
return null;
}
+ private static DexTypeList evaluateTypeArrayContent(
+ InvokeNewArray newArray, DexItemFactory factory) {
+ List<Value> arrayValues = newArray.inValues();
+ int size = arrayValues.size();
+ DexType[] values = new DexType[size];
+ for (int i = 0; i < size; ++i) {
+ DexType type = getTypeFromConstClassOrBoxedPrimitive(arrayValues.get(i), factory);
+ if (type == null) {
+ return null;
+ }
+ values[i] = type;
+ }
+ return new DexTypeList(values);
+ }
+
/**
* Visits all {@link ArrayPut}'s with the given {@param classListValue} as array and {@link Class}
* as value. Then collects all corresponding {@link DexType}s so as to determine reflective cases.
@@ -551,30 +571,13 @@
}
// Make sure this Value refers to a new array.
- if (!classListValue.definition.isNewArrayEmpty()
- || !classListValue.definition.asNewArrayEmpty().size().isConstant()) {
+ if (classListValue.definition.isNewArrayEmpty()) {
+ return evaluateTypeArrayContentFromConstructionToUse(
+ classListValue.definition.asNewArrayEmpty(), aliases, invoke, factory);
+ } else if (classListValue.definition.isInvokeNewArray()) {
+ return evaluateTypeArrayContent(classListValue.definition.asInvokeNewArray(), factory);
+ } else {
return null;
}
-
- int size =
- classListValue
- .definition
- .asNewArrayEmpty()
- .size()
- .getConstInstruction()
- .asConstNumber()
- .getIntValue();
- if (size == 0) {
- return DexTypeList.empty();
- }
-
- DexType[] arrayContent =
- evaluateTypeArrayContentFromConstructionToUse(
- classListValue.definition.asNewArrayEmpty(), aliases, size, invoke, factory);
-
- if (arrayContent == null) {
- return null;
- }
- return new DexTypeList(arrayContent);
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index 0dbea46..2e6fb53 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -87,11 +87,11 @@
private DexMethod getReboundMethodReference(DexMethod method) {
DexMethod rebound = nonReboundMethodReferenceToDefinitionMap.get(method);
+ assert method != rebound;
while (rebound != null) {
method = rebound;
rebound = nonReboundMethodReferenceToDefinitionMap.get(method);
}
- assert method != rebound;
return method;
}
diff --git a/src/main/java/com/android/tools/r8/references/FieldReference.java b/src/main/java/com/android/tools/r8/references/FieldReference.java
index dab6fd8..90f4b91 100644
--- a/src/main/java/com/android/tools/r8/references/FieldReference.java
+++ b/src/main/java/com/android/tools/r8/references/FieldReference.java
@@ -65,6 +65,14 @@
@Override
public String toString() {
- return getHolderClass().toString() + getFieldName() + ":" + getFieldType().getDescriptor();
+ return getHolderClass() + getFieldName() + ":" + getFieldType().getDescriptor();
+ }
+
+ public String toSourceString() {
+ return getFieldType().getTypeName()
+ + " "
+ + getHolderClass().getTypeName()
+ + "."
+ + getFieldName();
}
}
diff --git a/src/main/java/com/android/tools/r8/references/MethodReference.java b/src/main/java/com/android/tools/r8/references/MethodReference.java
index 5ef8596..3339916 100644
--- a/src/main/java/com/android/tools/r8/references/MethodReference.java
+++ b/src/main/java/com/android/tools/r8/references/MethodReference.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.Keep;
import com.android.tools.r8.KeepForRetraceApi;
-import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import java.util.List;
@@ -78,8 +77,7 @@
}
public String getMethodDescriptor() {
- return StringUtils.join(
- "", ListUtils.map(getFormalTypes(), TypeReference::getDescriptor), BraceType.PARENS)
+ return StringUtils.join("", getFormalTypes(), TypeReference::getDescriptor, BraceType.PARENS)
+ (getReturnType() == null ? "V" : getReturnType().getDescriptor());
}
@@ -87,4 +85,16 @@
public String toString() {
return getHolderClass() + getMethodName() + getMethodDescriptor();
}
+
+ public String toSourceString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(returnType == null ? "void" : returnType.getTypeName());
+ sb.append(" ");
+ sb.append(holderClass.getTypeName());
+ sb.append(".");
+ sb.append(methodName);
+ sb.append(
+ StringUtils.join(", ", getFormalTypes(), TypeReference::getTypeName, BraceType.PARENS));
+ return sb.toString();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceTypeElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceTypeElement.java
new file mode 100644
index 0000000..2df0a4c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceTypeElement.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, 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.retrace;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceTypeElement extends RetraceElement<RetraceTypeResult> {
+
+ RetracedTypeReference getType();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
index 30a4c5c..7925ff6 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceTypeResult.java
@@ -5,21 +5,6 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.Keep;
-import java.util.function.Consumer;
-import java.util.stream.Stream;
@Keep
-public interface RetraceTypeResult {
-
- Stream<Element> stream();
-
- RetraceTypeResult forEach(Consumer<Element> resultConsumer);
-
- boolean isAmbiguous();
-
- @Keep
- interface Element {
-
- RetracedTypeReference getType();
- }
-}
+public interface RetraceTypeResult extends RetraceResult<RetraceTypeElement> {}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetracedClassReference.java b/src/main/java/com/android/tools/r8/retrace/RetracedClassReference.java
index 99e85be..5e6b29b 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetracedClassReference.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetracedClassReference.java
@@ -12,6 +12,8 @@
String getTypeName();
+ String getDescriptor();
+
String getBinaryName();
RetracedTypeReference getRetracedType();
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java
index 6242c3b..d1ee952 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceTypeResultImpl.java
@@ -4,61 +4,94 @@
package com.android.tools.r8.retrace.internal;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.RetraceTypeElement;
import com.android.tools.r8.retrace.RetraceTypeResult;
import com.android.tools.r8.retrace.RetracedTypeReference;
import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.utils.ListUtils;
+import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
public class RetraceTypeResultImpl implements RetraceTypeResult {
private final TypeReference obfuscatedType;
+ private final List<RetracedTypeReference> retracedTypeReferences;
private final Retracer retracer;
- private RetraceTypeResultImpl(TypeReference obfuscatedType, Retracer retracer) {
+ private RetraceTypeResultImpl(
+ TypeReference obfuscatedType,
+ List<RetracedTypeReference> retracedTypeReferences,
+ Retracer retracer) {
this.obfuscatedType = obfuscatedType;
+ this.retracedTypeReferences = retracedTypeReferences;
this.retracer = retracer;
}
static RetraceTypeResultImpl create(TypeReference obfuscatedType, Retracer retracer) {
- return new RetraceTypeResultImpl(obfuscatedType, retracer);
+ // Handle void and primitive types as single element results.
+ return new RetraceTypeResultImpl(
+ obfuscatedType, retraceTypeReference(obfuscatedType, retracer), retracer);
+ }
+
+ private static List<RetracedTypeReference> retraceTypeReference(
+ TypeReference obfuscatedType, Retracer retracer) {
+ if (obfuscatedType == null) {
+ return Collections.emptyList();
+ } else if (obfuscatedType.isPrimitive()) {
+ return Collections.singletonList(RetracedTypeReferenceImpl.create(obfuscatedType));
+ } else if (obfuscatedType.isArray()) {
+ int dimensions = obfuscatedType.asArray().getDimensions();
+ List<RetracedTypeReference> baseTypeRetraceResult =
+ retraceTypeReference(obfuscatedType.asArray().getBaseType(), retracer);
+ return ListUtils.map(
+ baseTypeRetraceResult,
+ retraceTypeReference ->
+ RetracedTypeReferenceImpl.create(
+ Reference.array(retraceTypeReference.getTypeReference(), dimensions)));
+ } else {
+ assert obfuscatedType.isClass();
+ return retracer.retraceClass(obfuscatedType.asClass()).stream()
+ .map(clazz -> clazz.getRetracedClass().getRetracedType())
+ .collect(Collectors.toList());
+ }
}
@Override
- public Stream<Element> stream() {
- // Handle void and primitive types as single element results.
- if (obfuscatedType == null || obfuscatedType.isPrimitive()) {
- return Stream.of(new ElementImpl(RetracedTypeReferenceImpl.create(obfuscatedType)));
- }
- if (obfuscatedType.isArray()) {
- int dimensions = obfuscatedType.asArray().getDimensions();
- return retracer.retraceType(obfuscatedType.asArray().getBaseType()).stream()
- .map(
- baseElement ->
- new ElementImpl(
- RetracedTypeReferenceImpl.create(baseElement.getType().toArray(dimensions))));
- }
- return retracer.retraceClass(obfuscatedType.asClass()).stream()
- .map(classElement -> new ElementImpl(classElement.getRetracedClass().getRetracedType()));
+ public Stream<RetraceTypeElement> stream() {
+ List<RetraceTypeElement> map =
+ ListUtils.map(
+ retracedTypeReferences,
+ retracedTypeReference -> new ElementImpl(this, retracedTypeReference));
+ return map.stream();
}
@Override
public boolean isAmbiguous() {
- return false;
+ return retracedTypeReferences.size() > 1;
}
@Override
- public RetraceTypeResultImpl forEach(Consumer<Element> resultConsumer) {
+ public void forEach(Consumer<RetraceTypeElement> resultConsumer) {
stream().forEach(resultConsumer);
- return this;
}
- public static class ElementImpl implements RetraceTypeResult.Element {
+ @Override
+ public boolean isEmpty() {
+ return retracedTypeReferences.size() == 0;
+ }
+ public static class ElementImpl implements RetraceTypeElement {
+
+ private final RetraceTypeResult typeResult;
private final RetracedTypeReference retracedType;
- public ElementImpl(RetracedTypeReference retracedType) {
+ private ElementImpl(RetraceTypeResult typeResult, RetracedTypeReference retracedType) {
+ this.typeResult = typeResult;
this.retracedType = retracedType;
}
@@ -66,5 +99,15 @@
public RetracedTypeReference getType() {
return retracedType;
}
+
+ @Override
+ public RetraceTypeResult getParentResult() {
+ return typeResult;
+ }
+
+ @Override
+ public boolean isCompilerSynthesized() {
+ return false;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassReferenceImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassReferenceImpl.java
index ef23ef1..d036009 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassReferenceImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracedClassReferenceImpl.java
@@ -26,6 +26,11 @@
}
@Override
+ public String getDescriptor() {
+ return classReference.getDescriptor();
+ }
+
+ @Override
public String getBinaryName() {
return classReference.getBinaryName();
}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
index a8b5e71..c907105 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.retrace.RetraceStackTraceElementProxy;
import com.android.tools.r8.retrace.RetraceStackTraceElementProxyResult;
import com.android.tools.r8.retrace.RetraceThrownExceptionElement;
+import com.android.tools.r8.retrace.RetraceTypeElement;
import com.android.tools.r8.retrace.RetraceTypeResult;
-import com.android.tools.r8.retrace.RetraceTypeResult.Element;
import com.android.tools.r8.retrace.RetracedClassReference;
import com.android.tools.r8.retrace.RetracedFieldReference;
import com.android.tools.r8.retrace.RetracedMethodReference;
@@ -272,7 +272,8 @@
} else {
TypeReference typeReference = Reference.typeFromTypeName(elementOrReturnType);
RetraceTypeResult retraceTypeResult = retracer.retraceType(typeReference);
- List<Element> retracedElements = retraceTypeResult.stream().collect(Collectors.toList());
+ List<RetraceTypeElement> retracedElements =
+ retraceTypeResult.stream().collect(Collectors.toList());
return resultBuilder
.setResultStream(
currentResult.stream()
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 213819d..93d387e 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -104,7 +104,9 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
@@ -5079,25 +5081,43 @@
return;
}
Value parametersValue = constructorDefinition.inValues().get(1);
- if (parametersValue.isPhi() || !parametersValue.definition.isNewArrayEmpty()) {
+ if (parametersValue.isPhi()) {
// Give up, we can't tell which constructor is being invoked.
return;
}
-
- Value parametersSizeValue = parametersValue.definition.asNewArrayEmpty().size();
- if (parametersSizeValue.isPhi() || !parametersSizeValue.definition.isConstNumber()) {
- // Give up, we can't tell which constructor is being invoked.
+ NewArrayEmpty newArrayEmpty = parametersValue.definition.asNewArrayEmpty();
+ InvokeNewArray invokeNewArray = parametersValue.definition.asInvokeNewArray();
+ int parametersSize =
+ newArrayEmpty != null
+ ? newArrayEmpty.sizeIfConst()
+ : invokeNewArray != null ? invokeNewArray.size() : -1;
+ if (parametersSize < 0) {
return;
}
ProgramMethod initializer = null;
- int parametersSize = parametersSizeValue.definition.asConstNumber().getIntValue();
if (parametersSize == 0) {
initializer = clazz.getProgramDefaultInitializer();
} else {
DexType[] parameterTypes = new DexType[parametersSize];
int missingIndices = parametersSize;
+
+ if (newArrayEmpty != null) {
+ missingIndices = parametersSize;
+ } else {
+ missingIndices = 0;
+ List<Value> values = invokeNewArray.inValues();
+ for (int i = 0; i < parametersSize; ++i) {
+ DexType type =
+ ConstantValueUtils.getDexTypeRepresentedByValueForTracing(values.get(i), appView);
+ if (type == null) {
+ return;
+ }
+ parameterTypes[i] = type;
+ }
+ }
+
for (Instruction user : parametersValue.uniqueUsers()) {
if (user.isArrayPut()) {
ArrayPut arrayPutInstruction = user.asArrayPut();
@@ -5159,20 +5179,31 @@
}
Value interfacesValue = invoke.arguments().get(1);
- if (interfacesValue.isPhi() || !interfacesValue.definition.isNewArrayEmpty()) {
+ if (interfacesValue.isPhi()) {
// Give up, we can't tell which interfaces the proxy implements.
return;
}
- WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList();
- for (Instruction user : interfacesValue.uniqueUsers()) {
- if (!user.isArrayPut()) {
- continue;
+ InvokeNewArray invokeNewArray = interfacesValue.definition.asInvokeNewArray();
+ NewArrayEmpty newArrayEmpty = interfacesValue.definition.asNewArrayEmpty();
+ List<Value> values;
+ if (invokeNewArray != null) {
+ values = invokeNewArray.inValues();
+ } else if (newArrayEmpty != null) {
+ values = new ArrayList<>(interfacesValue.uniqueUsers().size());
+ for (Instruction user : interfacesValue.uniqueUsers()) {
+ ArrayPut arrayPut = user.asArrayPut();
+ if (arrayPut != null) {
+ values.add(arrayPut.value());
+ }
}
+ } else {
+ return;
+ }
- ArrayPut arrayPut = user.asArrayPut();
- DexType type =
- ConstantValueUtils.getDexTypeRepresentedByValueForTracing(arrayPut.value(), appView);
+ WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList();
+ for (Value value : values) {
+ DexType type = ConstantValueUtils.getDexTypeRepresentedByValueForTracing(value, appView);
if (type == null || !type.isClassType()) {
continue;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 7170817..57726f6 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -156,6 +156,11 @@
if (clazz == null) {
return;
}
+ if (clazz.isLibraryClass()) {
+ // TODO(b/259204069): Mitigation of invalid interface removal.
+ // It would be nice to integrate this with the api database.
+ return;
+ }
for (DexType itf : clazz.interfaces) {
if (interfaces.remove(itf) && interfaces.isEmpty()) {
return;
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index cdac93d..443b9e7 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -4,12 +4,11 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.structural.Ordered;
import java.util.Optional;
-/**
- * Android dex version
- */
-public enum DexVersion {
+/** Android dex version */
+public enum DexVersion implements Ordered<DexVersion> {
V35(35, new byte[] {'0', '3', '5'}),
V37(37, new byte[] {'0', '3', '7'}),
V38(38, new byte[] {'0', '3', '8'}),
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 e653a7a..98d5a27 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -816,6 +816,7 @@
public boolean debug = false;
+ private final RewriteArrayOptions rewriteArrayOptions = new RewriteArrayOptions();
private final CallSiteOptimizationOptions callSiteOptimizationOptions =
new CallSiteOptimizationOptions();
private final CfCodeAnalysisOptions cfCodeAnalysisOptions = new CfCodeAnalysisOptions();
@@ -850,6 +851,10 @@
public LineNumberOptimization lineNumberOptimization = LineNumberOptimization.ON;
+ public RewriteArrayOptions rewriteArrayOptions() {
+ return rewriteArrayOptions;
+ }
+
public CallSiteOptimizationOptions callSiteOptimizationOptions() {
return callSiteOptimizationOptions;
}
@@ -1383,6 +1388,42 @@
System.getProperty("com.android.tools.r8.lambdaClassFieldsNotFinal") == null;
}
+ public class RewriteArrayOptions {
+ // Arbitrary limit of number of inputs to new-filled-array/range.
+ // The technical limit is 255 (Constants.U8BIT_MAX).
+ public int maxRangeInputs = 200;
+ // Arbitrary limit of number of inputs to fill-array-data.
+ public int maxFillArrayDataInputs = 8 * 1024;
+
+ // Dalvik x86-atom backend had a bug that made it crash on filled-new-array instructions for
+ // arrays of objects. This is unfortunate, since this never hits arm devices, but we have
+ // to disallow filled-new-array of objects for dalvik until kitkat. The buggy code was
+ // removed during the jelly-bean release cycle and is not there from kitkat.
+ //
+ // Buggy code that accidentally call code that only works on primitives arrays.
+ //
+ // https://android.googlesource.com/platform/dalvik/+/ics-mr0/vm/mterp/out/InterpAsm-x86-atom.S#25106
+ public boolean canUseFilledNewArrayOfStrings() {
+ assert isGeneratingDex();
+ return hasFeaturePresentFrom(AndroidApiLevel.K);
+ }
+
+ // When adding support for emitting new-filled-array for non-String types, ART 6.0.1 had issues.
+ // https://ci.chromium.org/ui/p/r8/builders/ci/linux-android-6.0.1/6507/overview
+ // It somehow had a new-array-filled return null.
+ public boolean canUseFilledNewArrayOfObjects() {
+ assert isGeneratingDex();
+ return hasFeaturePresentFrom(AndroidApiLevel.N);
+ }
+
+ // Dalvik doesn't handle new-filled-array with arrays as values. It fails with:
+ // W(629880) VFY: [Ljava/lang/Integer; is not instance of Ljava/lang/Integer; (dalvikvm)
+ public boolean canUseFilledNewArrayOfArrays() {
+ assert isGeneratingDex();
+ return hasFeaturePresentFrom(AndroidApiLevel.L);
+ }
+ }
+
public class CallSiteOptimizationOptions {
private boolean enabled = true;
@@ -2387,19 +2428,6 @@
return hasFeaturePresentFrom(AndroidApiLevel.J);
}
- // Dalvik x86-atom backend had a bug that made it crash on filled-new-array instructions for
- // arrays of objects. This is unfortunate, since this never hits arm devices, but we have
- // to disallow filled-new-array of objects for dalvik until kitkat. The buggy code was
- // removed during the jelly-bean release cycle and is not there from kitkat.
- //
- // Buggy code that accidentally call code that only works on primitives arrays.
- //
- // https://android.googlesource.com/platform/dalvik/+/ics-mr0/vm/mterp/out/InterpAsm-x86-atom.S#25106
- public boolean canUseFilledNewArrayOfObjects() {
- assert isGeneratingDex();
- return hasFeaturePresentFrom(AndroidApiLevel.K);
- }
-
// Art had a bug (b/68761724) for Android N and O in the arm32 interpreter
// where an aget-wide instruction using the same register for the array
// and the first register of the result could lead to the wrong exception
diff --git a/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java b/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java
new file mode 100644
index 0000000..1c5f9b3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java
@@ -0,0 +1,176 @@
+// Copyright (c) 2022, 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.utils;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.IndexedDexItem;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.retrace.RetraceClassElement;
+import com.android.tools.r8.retrace.RetraceElement;
+import com.android.tools.r8.retrace.RetraceMethodResult;
+import com.android.tools.r8.retrace.RetraceResult;
+import com.android.tools.r8.retrace.RetracedFieldReference;
+import com.android.tools.r8.retrace.RetracedFieldReference.KnownRetracedFieldReference;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.RetracedMethodReference.KnownRetracedMethodReference;
+import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.retrace.internal.MappingSupplierInternalImpl;
+import com.android.tools.r8.retrace.internal.RetracerImpl;
+import java.util.function.Function;
+
+public class RetracerForCodePrinting {
+
+ private static final RetracerForCodePrinting EMPTY = new RetracerForCodePrinting(null);
+
+ public static RetracerForCodePrinting empty() {
+ return EMPTY;
+ }
+
+ private final Retracer retracer;
+
+ private RetracerForCodePrinting(Retracer retracer) {
+ this.retracer = retracer;
+ }
+
+ public static RetracerForCodePrinting create(
+ ClassNameMapper classNameMapper, DiagnosticsHandler handler) {
+ return classNameMapper == null
+ ? empty()
+ : new RetracerForCodePrinting(
+ RetracerImpl.createInternal(
+ MappingSupplierInternalImpl.createInternal(classNameMapper), handler));
+ }
+
+ public <T extends RetraceElement<?>> String joinAmbiguousResults(
+ RetraceResult<T> retraceResult, Function<T, String> nameToString) {
+ return StringUtils.join(" <OR> ", retraceResult.stream(), nameToString);
+ }
+
+ private String typeToString(
+ DexType type,
+ Function<DexType, String> noRetraceString,
+ Function<RetraceClassElement, String> retraceResult) {
+ return retracer == null
+ ? noRetraceString.apply(type)
+ : joinAmbiguousResults(retracer.retraceClass(type.asClassReference()), retraceResult);
+ }
+
+ public String toSourceString(DexType type) {
+ return typeToString(
+ type, DexType::toSourceString, element -> element.getRetracedClass().getTypeName());
+ }
+
+ public String toDescriptor(DexType type) {
+ return typeToString(
+ type, DexType::toDescriptorString, element -> element.getRetracedClass().getDescriptor());
+ }
+
+ private String retraceMethodToString(
+ DexMethod method,
+ Function<DexMethod, String> noRetraceString,
+ Function<KnownRetracedMethodReference, String> knownToString,
+ Function<RetracedMethodReference, String> unknownToString) {
+ if (retracer == null) {
+ return noRetraceString.apply(method);
+ }
+ // TODO(b/169953605): Use retracer.retraceMethod() when we have enough information.
+ MethodReference methodReference = method.asMethodReference();
+ RetraceMethodResult retraceMethodResult =
+ retracer
+ .retraceClass(methodReference.getHolderClass())
+ .lookupMethod(methodReference.getMethodName());
+ return joinAmbiguousResults(
+ retraceMethodResult,
+ element -> {
+ if (element.isUnknown()) {
+ return unknownToString.apply(element.getRetracedMethod());
+ } else {
+ return knownToString.apply(element.getRetracedMethod().asKnown());
+ }
+ });
+ }
+
+ public String toSourceString(DexMethod method) {
+ return retraceMethodToString(
+ method,
+ DexMethod::toSourceString,
+ knownRetracedMethodReference ->
+ knownRetracedMethodReference.getMethodReference().toSourceString(),
+ unknown -> unknown.getHolderClass().getTypeName() + " " + unknown.getMethodName());
+ }
+
+ public String toDescriptor(DexMethod method) {
+ return retraceMethodToString(
+ method,
+ m -> m.asMethodReference().toString(),
+ knownRetracedMethodReference ->
+ knownRetracedMethodReference.getMethodReference().toString(),
+ unknown -> unknown.getHolderClass().getDescriptor() + unknown.getMethodName());
+ }
+
+ private String retraceFieldToString(
+ DexField field,
+ Function<DexField, String> noRetraceString,
+ Function<KnownRetracedFieldReference, String> knownToString,
+ Function<RetracedFieldReference, String> unknownToString) {
+ if (retracer == null) {
+ return noRetraceString.apply(field);
+ }
+ // TODO(b/169953605): Use retracer.retraceField() when we have enough information.
+ FieldReference fieldReference = field.asFieldReference();
+ return joinAmbiguousResults(
+ retracer
+ .retraceClass(fieldReference.getHolderClass())
+ .lookupField(fieldReference.getFieldName()),
+ element -> {
+ if (element.isUnknown()) {
+ return unknownToString.apply(element.getField());
+ } else {
+ return knownToString.apply(element.getField().asKnown());
+ }
+ });
+ }
+
+ public String toSourceString(DexField field) {
+ return retraceFieldToString(
+ field,
+ f -> f.asFieldReference().toSourceString(),
+ known -> known.getFieldReference().toSourceString(),
+ unknown -> unknown.getHolderClass().getDescriptor() + " " + unknown.getFieldName());
+ }
+
+ public String toDescriptor(DexField field) {
+ return retraceFieldToString(
+ field,
+ f -> f.asFieldReference().toString(),
+ known -> known.getFieldReference().toString(),
+ unknown -> unknown.getHolderClass().getDescriptor() + unknown.getFieldName());
+ }
+
+ public String toDescriptor(IndexedDexItem item) {
+ if (!(item instanceof DexReference)) {
+ return item.toString();
+ }
+ return ((DexReference) item).apply(this::toDescriptor, this::toDescriptor, this::toDescriptor);
+ }
+
+ public String toSourceString(IndexedDexItem item) {
+ if (!(item instanceof DexReference)) {
+ return item.toSourceString();
+ }
+ return ((DexReference) item)
+ .apply(this::toSourceString, this::toSourceString, this::toSourceString);
+ }
+
+ public boolean isEmpty() {
+ return this == EMPTY;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index f1e4e18..69cef74 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -15,6 +15,8 @@
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class StringUtils {
public static char[] EMPTY_CHAR_ARRAY = {};
@@ -143,6 +145,15 @@
return join(separator, iterable, fn, BraceType.NONE);
}
+ public static <T> String join(String separator, Stream<T> stream, Function<T, String> fn) {
+ return join(separator, stream.collect(Collectors.toList()), fn, BraceType.NONE);
+ }
+
+ public static <T> String join(
+ String separator, T[] elements, Function<T, String> fn, BraceType brace) {
+ return join(separator, Arrays.asList(elements), fn, brace);
+ }
+
public static <T> String join(String separator, Iterable<T> iterable, BraceType brace) {
return join(separator, iterable, Object::toString, brace);
}
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingIterator.java b/src/main/java/com/android/tools/r8/utils/ThrowingIterator.java
index 50d23c9..7d41ae1 100644
--- a/src/main/java/com/android/tools/r8/utils/ThrowingIterator.java
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingIterator.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.utils;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
@@ -32,4 +33,18 @@
}
return result;
}
+
+ public static <T, E extends Exception> ThrowingIterator<T, E> fromIterator(Iterator<T> it) {
+ return new ThrowingIterator<>() {
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public T next() throws E {
+ return it.next();
+ }
+ };
+ }
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 0230b46..5c73e63 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.keepanno.utils.Unimplemented;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.shaking.FilteredClassPath;
@@ -32,6 +33,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.AndroidAppConsumers;
+import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -66,6 +68,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -712,12 +715,28 @@
private static final Path DX = getDxExecutablePath();
private static Path getDexVmPath(DexVm vm) {
- return Paths.get(
- TOOLS,
- "linux",
- vm.getVersion() == DexVm.Version.DEFAULT
- ? "art"
- : "art-" + vm.getVersion());
+ DexVm.Version version = vm.getVersion();
+ Path base = Paths.get(TOOLS, "linux");
+ switch (version) {
+ case DEFAULT:
+ return base.resolve("art");
+ case V4_0_4:
+ case V4_4_4:
+ case V5_1_1:
+ case V6_0_1:
+ case V7_0_0:
+ case V8_1_0:
+ case V9_0_0:
+ case V10_0_0:
+ return base.resolve("art-" + version);
+ case V12_0_0:
+ return base.resolve("host").resolve("art-12.0.0-beta4");
+ case V13_0_0:
+ case MASTER:
+ return base.resolve("host").resolve("art-" + version);
+ default:
+ throw new Unreachable();
+ }
}
private static Path getDexVmLibPath(DexVm vm) {
@@ -733,7 +752,25 @@
}
private static String getArchString(DexVm vm) {
- return vm.isOlderThanOrEqual(DexVm.ART_5_1_1_HOST) ? "arm" : "arm64";
+ switch (vm.getVersion()) {
+ case V4_0_4:
+ case V4_4_4:
+ case V5_1_1:
+ return "arm";
+ case V6_0_1:
+ case V7_0_0:
+ case V8_1_0:
+ case DEFAULT:
+ case V9_0_0:
+ case V10_0_0:
+ return "arm64";
+ case V12_0_0:
+ case V13_0_0:
+ case MASTER:
+ return "x86_64";
+ default:
+ throw new Unimplemented();
+ }
}
private static Path getProductBootImagePath(DexVm vm) {
@@ -1057,6 +1094,10 @@
}
}
+ public static DexVersion getDexFileVersionForVm(DexVm vm) {
+ return DexVersion.getDexVersion(getMinApiLevelForDexVm(vm));
+ }
+
private static String getPlatform() {
return System.getProperty("os.name");
}
@@ -1992,34 +2033,56 @@
}
}
- public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException {
- // TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
+ // Checked in VMs for which dex2oat should work specified in decreasing order.
+ private static List<DexVm> SUPPORTED_DEX2OAT_VMS =
+ ImmutableList.of(DexVm.ART_12_0_0_HOST, DexVm.ART_6_0_1_HOST);
+
+ public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm targetVm)
+ throws IOException {
Assume.assumeTrue(ToolHelper.isDex2OatSupported());
- Assume.assumeFalse(
- "b/144975341",
- vm.version == DexVm.Version.V10_0_0
- || vm.version == DexVm.Version.V12_0_0
- || vm.version == DexVm.Version.V13_0_0);
- if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
- // Run default dex2oat for tests on dalvik runtimes.
- vm = DexVm.ART_DEFAULT;
- }
assert Files.exists(file);
assert ByteStreams.toByteArray(Files.newInputStream(file)).length > 0;
+ assert SUPPORTED_DEX2OAT_VMS.stream()
+ .sorted(Comparator.comparing(DexVm::getVersion).reversed())
+ .collect(Collectors.toList())
+ .equals(SUPPORTED_DEX2OAT_VMS);
+ DexVersion requiredDexFileVersion = getDexFileVersionForVm(targetVm);
+ DexVm vm = null;
+ for (DexVm supported : SUPPORTED_DEX2OAT_VMS) {
+ DexVersion supportedDexFileVersion = getDexFileVersionForVm(supported);
+ // This and remaining VMs can't compile code at the required DEX version.
+ if (supportedDexFileVersion.isLessThan(requiredDexFileVersion)) {
+ break;
+ }
+ // Find the "oldest" supported VM. Only consider VMs older than targetVm if no VM matched.
+ if (supported.isNewerThanOrEqual(targetVm) || vm == null) {
+ vm = supported;
+ }
+ }
+ if (vm == null) {
+ throw new Unimplemented("Unable to find a supported dex2oat for VM " + vm);
+ }
List<String> command = new ArrayList<>();
- command.add(getDex2OatPath(vm).toString());
- command.add("--android-root=" + getProductPath(vm) + "/system");
+ command.add(getDex2OatPath(vm).toAbsolutePath().toString());
+ command.add("--android-root=" + getProductPath(vm).toAbsolutePath() + "/system");
command.add("--runtime-arg");
command.add("-verbose:verifier");
command.add("--runtime-arg");
command.add("-Xnorelocate");
command.add("--dex-file=" + file.toAbsolutePath());
command.add("--oat-file=" + outFile.toAbsolutePath());
- // TODO(zerny): Create a proper interface for invoking dex2oat. Hardcoding arch here is a hack!
command.add("--instruction-set=" + getArchString(vm));
+ if (vm.version.equals(DexVm.Version.V12_0_0)) {
+ command.add(
+ "--boot-image="
+ + getDexVmPath(vm).toAbsolutePath()
+ + "/apex/art_boot_images/javalib/boot.art");
+ }
ProcessBuilder builder = new ProcessBuilder(command);
+ builder.directory(getDexVmPath(vm).toFile());
builder.environment().put("LD_LIBRARY_PATH", getDexVmLibPath(vm).toString());
- return runProcess(builder);
+ ProcessResult processResult = runProcess(builder);
+ return processResult;
}
public static ProcessResult runProguardRaw(
@@ -2192,8 +2255,15 @@
public static ProcessResult runProcess(ProcessBuilder builder, PrintStream out)
throws IOException {
+ boolean printCwd = builder.directory() != null;
+ if (printCwd) {
+ out.println("(cd " + builder.directory().toString() + "; ");
+ }
String command = String.join(" ", builder.command());
out.println(command);
+ if (printCwd) {
+ out.println(")");
+ }
return drainProcessOutputStreams(builder.start(), command);
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockAbstractMethodOnBaseToOutlineTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockAbstractMethodOnBaseToOutlineTest.java
new file mode 100644
index 0000000..380702e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockAbstractMethodOnBaseToOutlineTest.java
@@ -0,0 +1,186 @@
+// Copyright (c) 2022, 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.apimodel;
+
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.testing.AndroidBuildVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ApiModelMockAbstractMethodOnBaseToOutlineTest extends TestBase {
+
+ private final AndroidApiLevel subMockLevel = AndroidApiLevel.M;
+
+ @Parameter public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ private boolean isGreaterOrEqualToMockLevel() {
+ return parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(subMockLevel);
+ }
+
+ private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+ testBuilder
+ .addProgramClasses(Main.class)
+ .addLibraryClasses(
+ LibraryClass.class, OtherLibraryClass.class, SubLibraryClassAtLaterApiLevel.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .setMinApi(parameters.getApiLevel())
+ .addAndroidBuildVersion()
+ .apply(ApiModelingTestHelper::enableStubbingOfClasses)
+ .apply(ApiModelingTestHelper::enableOutliningOfMethods)
+ .apply(setMockApiLevelForClass(LibraryClass.class, AndroidApiLevel.B))
+ .apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, AndroidApiLevel.B))
+ .apply(
+ setMockApiLevelForMethod(
+ LibraryClass.class.getDeclaredMethod("foo"), AndroidApiLevel.B))
+ .apply(
+ setMockApiLevelForMethod(
+ OtherLibraryClass.class.getDeclaredMethod("baz"), subMockLevel))
+ .apply(setMockApiLevelForClass(SubLibraryClassAtLaterApiLevel.class, subMockLevel))
+ .apply(
+ setMockApiLevelForDefaultInstanceInitializer(
+ SubLibraryClassAtLaterApiLevel.class, subMockLevel))
+ .apply(
+ setMockApiLevelForMethod(
+ SubLibraryClassAtLaterApiLevel.class.getDeclaredMethod("foo"), subMockLevel));
+ }
+
+ @Test
+ public void testD8Debug() throws Exception {
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .inspect(this::inspect)
+ .addBootClasspathClasses(LibraryClass.class)
+ .applyIf(
+ isGreaterOrEqualToMockLevel(),
+ b ->
+ b.addBootClasspathClasses(
+ OtherLibraryClass.class, SubLibraryClassAtLaterApiLevel.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(runResult -> checkOutput(runResult, false));
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .inspect(this::inspect)
+ .addBootClasspathClasses(LibraryClass.class)
+ .applyIf(
+ isGreaterOrEqualToMockLevel(),
+ b ->
+ b.addBootClasspathClasses(
+ OtherLibraryClass.class, SubLibraryClassAtLaterApiLevel.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(runResult -> checkOutput(runResult, true));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .apply(this::setupTestBuilder)
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .compile()
+ .inspect(this::inspect)
+ .addBootClasspathClasses(LibraryClass.class)
+ .applyIf(
+ isGreaterOrEqualToMockLevel(),
+ b ->
+ b.addBootClasspathClasses(
+ OtherLibraryClass.class, SubLibraryClassAtLaterApiLevel.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(runResult -> checkOutput(runResult, true));
+ }
+
+ private void checkOutput(SingleTestRunResult<?> runResult, boolean isRelease) {
+ if (isGreaterOrEqualToMockLevel()) {
+ runResult.assertSuccessWithOutputLines(
+ "OtherLibraryClass::foo", "SubLibraryClassAtLaterApiLevel::foo");
+ } else {
+ runResult.assertSuccessWithOutputLines("NoClassDefFoundError");
+ }
+ runResult.applyIf(
+ !isGreaterOrEqualToMockLevel()
+ && parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0),
+ result -> result.assertStderrMatches(not(containsString("This dex file is invalid"))));
+ }
+
+ private void inspect(CodeInspector inspector) {
+ assertThat(inspector.clazz(SubLibraryClassAtLaterApiLevel.class), isAbsent());
+ }
+
+ public abstract static class LibraryClass {
+
+ public abstract void foo();
+ }
+
+ public static class SubLibraryClassAtLaterApiLevel extends LibraryClass {
+
+ @Override
+ public void foo() {
+ System.out.println("SubLibraryClassAtLaterApiLevel::foo");
+ }
+ }
+
+ public static class OtherLibraryClass {
+
+ public static void baz() {
+ System.out.println("OtherLibraryClass::foo");
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ try {
+ OtherLibraryClass.baz();
+ if (AndroidBuildVersion.VERSION >= 23) {
+ callSubFoo(new SubLibraryClassAtLaterApiLevel());
+ } else if (System.currentTimeMillis() == 0) {
+ callSubFoo(new Object());
+ }
+ } catch (NoClassDefFoundError e) {
+ System.out.println("NoClassDefFoundError");
+ }
+ }
+
+ @NeverInline
+ private static void callSubFoo(Object o) {
+ ((SubLibraryClassAtLaterApiLevel) o).foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
similarity index 66%
copy from src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
copy to src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
index b80d79c..05c405f 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassCheckCastTest.java
@@ -1,13 +1,14 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2022, 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.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -17,7 +18,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -28,7 +28,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class ApiModelMockClassLoadingTest extends TestBase {
+public class ApiModelMockClassCheckCastTest extends TestBase {
private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
@@ -36,7 +36,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
private boolean isGreaterOrEqualToMockLevel() {
@@ -54,9 +54,17 @@
}
@Test
+ public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+ testForJvm()
+ .addProgramClasses(Main.class, TestClass.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
public void testD8Debug() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
@@ -68,8 +76,7 @@
@Test
public void testD8Release() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
@@ -94,12 +101,10 @@
private void checkOutput(SingleTestRunResult<?> runResult) {
if (isGreaterOrEqualToMockLevel()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else if (parameters.isDexRuntime()
- && parameters.asDexRuntime().getVm().isEqualTo(DexVm.ART_4_4_4_HOST)) {
- runResult.assertSuccessWithOutputLines("ClassNotFoundException");
+ runResult.assertSuccessWithOutputLines("false", "checkcast caused ClassCastException");
} else {
- runResult.assertSuccessWithOutputLines("NoClassDefFoundError");
+ runResult.assertSuccessWithOutputLines(
+ "instanceof caused NoClassDefFoundError", "checkcast caused NoClassDefFoundError");
}
runResult.applyIf(
!isGreaterOrEqualToMockLevel()
@@ -109,7 +114,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
// Only present from api level 23.
@@ -118,14 +123,22 @@
public static class TestClass {
@NeverInline
- public static void test() {
+ public static void testInstanceOf(Object o) {
try {
- Class.forName(LibraryClass.class.getName());
- System.out.println("Hello World!");
- } catch (ExceptionInInitializerError | NoClassDefFoundError er) {
- System.out.println("NoClassDefFoundError");
- } catch (ClassNotFoundException e) {
- System.out.println("ClassNotFoundException");
+ System.out.println(o instanceof LibraryClass);
+ } catch (NoClassDefFoundError ex) {
+ System.out.println("instanceof caused NoClassDefFoundError");
+ }
+ }
+
+ @NeverInline
+ public static void testCheckCast(Object o) {
+ try {
+ System.out.println(((LibraryClass) o).getClass().getName());
+ } catch (NoClassDefFoundError e) {
+ System.out.println("checkcast caused NoClassDefFoundError");
+ } catch (ClassCastException e) {
+ System.out.println("checkcast caused ClassCastException");
}
}
}
@@ -133,7 +146,15 @@
public static class Main {
public static void main(String[] args) {
- TestClass.test();
+ if (System.currentTimeMillis() > 0) {
+ Object o = new Object();
+ TestClass.testInstanceOf(o);
+ TestClass.testCheckCast(o);
+ } else {
+ LibraryClass libraryClass = new LibraryClass();
+ TestClass.testInstanceOf(libraryClass);
+ TestClass.testCheckCast(libraryClass);
+ }
}
}
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
similarity index 77%
copy from src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
copy to src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
index b80d79c..0b76660 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassForNameTest.java
@@ -5,9 +5,10 @@
package com.android.tools.r8.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -17,7 +18,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -28,7 +28,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class ApiModelMockClassLoadingTest extends TestBase {
+public class ApiModelMockClassLoadingByClassForNameTest extends TestBase {
private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
@@ -36,7 +36,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
private boolean isGreaterOrEqualToMockLevel() {
@@ -54,9 +54,17 @@
}
@Test
+ public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+ testForJvm()
+ .addProgramClasses(Main.class, TestClass.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
public void testD8Debug() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
@@ -68,8 +76,7 @@
@Test
public void testD8Release() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
@@ -95,11 +102,8 @@
private void checkOutput(SingleTestRunResult<?> runResult) {
if (isGreaterOrEqualToMockLevel()) {
runResult.assertSuccessWithOutputLines("Hello World!");
- } else if (parameters.isDexRuntime()
- && parameters.asDexRuntime().getVm().isEqualTo(DexVm.ART_4_4_4_HOST)) {
- runResult.assertSuccessWithOutputLines("ClassNotFoundException");
} else {
- runResult.assertSuccessWithOutputLines("NoClassDefFoundError");
+ runResult.assertSuccessWithOutputLines("ClassNotFoundException");
}
runResult.applyIf(
!isGreaterOrEqualToMockLevel()
@@ -109,7 +113,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
// Only present from api level 23.
@@ -120,9 +124,14 @@
@NeverInline
public static void test() {
try {
- Class.forName(LibraryClass.class.getName());
+ String className =
+ "com.android.tools.r8.apimodel.ApiModelMockClassLoadingByClassForNameTest$LibraryClass"
+ + (System.currentTimeMillis() == 0 ? "asdf" : "");
+ Class.forName(className);
System.out.println("Hello World!");
- } catch (ExceptionInInitializerError | NoClassDefFoundError er) {
+ } catch (ExceptionInInitializerError er) {
+ System.out.println("ExceptionInInitializerError");
+ } catch (NoClassDefFoundError er) {
System.out.println("NoClassDefFoundError");
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFoundException");
@@ -134,6 +143,9 @@
public static void main(String[] args) {
TestClass.test();
+ if (System.currentTimeMillis() == 0) {
+ System.out.println(LibraryClass.class.getName());
+ }
}
}
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
similarity index 80%
rename from src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
rename to src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
index b80d79c..9074fcc 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassLoadingByClassReferenceTest.java
@@ -1,13 +1,14 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2022, 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.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -17,7 +18,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -28,7 +28,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class ApiModelMockClassLoadingTest extends TestBase {
+public class ApiModelMockClassLoadingByClassReferenceTest extends TestBase {
private final AndroidApiLevel mockLevel = AndroidApiLevel.M;
@@ -36,7 +36,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
private boolean isGreaterOrEqualToMockLevel() {
@@ -54,9 +54,17 @@
}
@Test
+ public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime() && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+ testForJvm()
+ .addProgramClasses(Main.class, TestClass.class)
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
public void testD8Debug() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
@@ -68,8 +76,7 @@
@Test
public void testD8Release() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
+ testForD8(parameters.getBackend())
.setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
@@ -94,10 +101,7 @@
private void checkOutput(SingleTestRunResult<?> runResult) {
if (isGreaterOrEqualToMockLevel()) {
- runResult.assertSuccessWithOutputLines("Hello World!");
- } else if (parameters.isDexRuntime()
- && parameters.asDexRuntime().getVm().isEqualTo(DexVm.ART_4_4_4_HOST)) {
- runResult.assertSuccessWithOutputLines("ClassNotFoundException");
+ runResult.assertSuccessWithOutputLines(typeName(LibraryClass.class));
} else {
runResult.assertSuccessWithOutputLines("NoClassDefFoundError");
}
@@ -109,7 +113,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
// Only present from api level 23.
@@ -120,12 +124,9 @@
@NeverInline
public static void test() {
try {
- Class.forName(LibraryClass.class.getName());
- System.out.println("Hello World!");
+ System.out.println(new LibraryClass().getClass().getName());
} catch (ExceptionInInitializerError | NoClassDefFoundError er) {
System.out.println("NoClassDefFoundError");
- } catch (ClassNotFoundException e) {
- System.out.println("ClassNotFoundException");
}
}
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
index cff8d68..ac98967 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockClassTest.java
@@ -6,11 +6,9 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -21,7 +19,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -133,18 +130,7 @@
.compile()
.writeToZip();
- if (isGreaterOrEqualToMockLevel()) {
- assertFalse(globals.hasGlobals());
- } else if (outputMode == OutputMode.DexIndexed) {
- assertTrue(globals.hasGlobals());
- assertTrue(globals.isSingleGlobal());
- } else {
- assertTrue(globals.hasGlobals());
- // The TestClass does reference the mock and should have globals.
- assertNotNull(globals.getProvider(Reference.classFromClass(TestClass.class)));
- // The Main class does not have references to the mock and should have no globals.
- assertNull(globals.getProvider(Reference.classFromClass(Main.class)));
- }
+ assertFalse(globals.hasGlobals());
testForD8()
.debug()
@@ -172,7 +158,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockDalvikVerifyErrorTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockDalvikVerifyErrorTest.java
index 50edd76..1a5cd80 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockDalvikVerifyErrorTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockDalvikVerifyErrorTest.java
@@ -7,7 +7,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -109,7 +110,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
public abstract static class LibraryClass {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 322b30f..5d32ca1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -6,7 +6,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -97,7 +98,7 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
index 409cd9b..0ca565f 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeProgramDefinedDuplicateTest.java
@@ -10,7 +10,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
@@ -19,7 +18,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -102,17 +100,8 @@
paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
assertFalse(mainGlobals.hasGlobals());
- if (isGreaterOrEqualToMockLevel()) {
- assertFalse(testCallingFooGlobals.hasGlobals());
- assertFalse(testCallingBarGlobals.hasGlobals());
- } else {
- // The TestCallingX does reference the mock and should have globals.
- assertNotNull(
- testCallingFooGlobals.getProvider(Reference.classFromClass(TestCallingFoo.class)));
- assertNotNull(
- testCallingBarGlobals.getProvider(Reference.classFromClass(TestCallingBar.class)));
- }
-
+ assertFalse(testCallingFooGlobals.hasGlobals());
+ assertFalse(testCallingBarGlobals.hasGlobals());
testForD8()
.setMode(mode)
.addProgramFiles(paths)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
index b2611de..01681c4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockMergeTest.java
@@ -8,10 +8,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
@@ -20,7 +18,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -103,17 +100,8 @@
paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
assertFalse(mainGlobals.hasGlobals());
- if (isGreaterOrEqualToMockLevel()) {
- assertFalse(testCallingFooGlobals.hasGlobals());
- assertFalse(testCallingBarGlobals.hasGlobals());
- } else {
- // The TestCallingX does reference the mock and should have globals.
- assertNotNull(
- testCallingFooGlobals.getProvider(Reference.classFromClass(TestCallingFoo.class)));
- assertNotNull(
- testCallingBarGlobals.getProvider(Reference.classFromClass(TestCallingBar.class)));
- }
-
+ assertFalse(testCallingFooGlobals.hasGlobals());
+ assertFalse(testCallingBarGlobals.hasGlobals());
testForD8()
.setMode(mode)
.addProgramFiles(paths)
@@ -132,13 +120,7 @@
private void inspect(CodeInspector inspector) {
ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class);
- if (isGreaterOrEqualToMockLevel()) {
- assertThat(libraryClassSubject, isAbsent());
- } else {
- assertThat(libraryClassSubject, isPresent());
- assertThat(libraryClassSubject.uniqueMethodWithOriginalName("foo"), isAbsent());
- assertThat(libraryClassSubject.uniqueMethodWithOriginalName("bar"), isAbsent());
- }
+ assertThat(libraryClassSubject, isAbsent());
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index 5d4fc8f..a45f683 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -6,7 +6,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -121,9 +122,9 @@
}
private void inspect(CodeInspector inspector) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel);
- verifyThat(inspector, parameters, LibraryInterface.class).stubbedUntil(lowerMockApiLevel);
- verifyThat(inspector, parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
+ assertThat(inspector.clazz(LibraryInterface.class), isAbsent());
+ assertThat(inspector.clazz(OtherLibraryClass.class), isAbsent());
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index 4bb470c..37e361c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -116,11 +116,7 @@
} else {
verifyThat(inspector, parameters, methodOn23).isNotOutlinedFrom(mainMethod);
}
- if (canStub) {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryApiLevel);
- } else {
- assertThat(inspector.clazz(LibraryClass.class), isAbsent());
- }
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
}
// Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index 3504527..01894d1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -7,6 +7,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationMode;
@@ -104,7 +106,7 @@
}
private void inspect(CodeInspector inspector) throws Exception {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
+ assertThat(inspector.clazz(LibraryClass.class), isAbsent());
verifyThat(inspector, parameters, apiMethod())
.isOutlinedFromUntil(
Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
diff --git a/src/test/java/com/android/tools/r8/apimodel/NewInstanceToAbstractClassReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/NewInstanceToAbstractClassReferenceTest.java
new file mode 100644
index 0000000..b733845
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/apimodel/NewInstanceToAbstractClassReferenceTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2022, 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.apimodel;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NewInstanceToAbstractClassReferenceTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class)
+ .addProgramClassFileData(
+ transformer(A.class).setAccessFlags(ClassAccessFlags::setAbstract).transform())
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrowsIf(parameters.isCfRuntime(), InstantiationError.class)
+ .applyIf(
+ parameters.isDexRuntime(),
+ result -> {
+ if (parameters.getDexRuntimeVersion().isDalvik()) {
+ result.assertStderrMatches(
+ containsString(
+ "VFY: new-instance on interface or abstract class " + descriptor(A.class)));
+
+ } else if (parameters.getDexRuntimeVersion().isOlderThan(Version.V7_0_0)) {
+ result.assertStderrMatches(
+ containsString(
+ "Verification failed on class "
+ + typeName(NewInstanceToAbstractClassReferenceTest.class)));
+ } else {
+ result.assertStderrMatches(not(containsString("Verification failed")));
+ }
+ });
+ }
+
+ public static class A {
+
+ public void foo() {
+ System.out.println("A::foo");
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new A().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index 1f9e6c7..7799ba7 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -1021,7 +1021,7 @@
assertThat(method, isPresent());
assertThat(
method.getMethod().getCode().asCfCode().toString(),
- containsString("invokeinterface classmerging.MergeDefaultMethodIntoClassTest$A.f()V"));
+ containsString("invokeinterface Lclassmerging/MergeDefaultMethodIntoClassTest$A;f()V"));
runTestOnInput(
testForR8(parameters.getBackend())
diff --git a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
index 812eb63..b00d78b 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
@@ -10,7 +10,9 @@
import com.android.tools.r8.dex.code.DexConst4;
import com.android.tools.r8.dex.code.DexConstClass;
import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
import com.android.tools.r8.dex.code.DexInvokeVirtual;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
import com.android.tools.r8.dex.code.DexNewArray;
import com.android.tools.r8.dex.code.DexReturnVoid;
import com.android.tools.r8.graph.DexCode;
@@ -93,16 +95,29 @@
assertTrue(method.isPresent());
DexCode code = method.getMethod().getCode().asDexCode();
- assertTrue(code.instructions[0] instanceof DexConst4);
- assertTrue(code.instructions[1] instanceof DexNewArray);
- assertTrue(code.instructions[2] instanceof DexConst4);
- assertTrue(code.instructions[3] instanceof DexConstClass);
- assertTrue(code.instructions[4] instanceof DexAputObject);
- assertTrue(code.instructions[5] instanceof DexConstClass);
- assertTrue(code.instructions[6] instanceof DexConstString);
- assertNotEquals("foo", code.instructions[6].asConstString().getString().toString());
- assertTrue(code.instructions[7] instanceof DexInvokeVirtual);
- assertTrue(code.instructions[8] instanceof DexReturnVoid);
+
+ // Accept either array construction style (differs based on minSdkVersion).
+ if (code.instructions[1] instanceof DexFilledNewArray) {
+ assertTrue(code.instructions[0] instanceof DexConstClass);
+ assertTrue(code.instructions[1] instanceof DexFilledNewArray);
+ assertTrue(code.instructions[2] instanceof DexMoveResultObject);
+ assertTrue(code.instructions[3] instanceof DexConstClass);
+ assertTrue(code.instructions[4] instanceof DexConstString);
+ assertNotEquals("foo", code.instructions[4].asConstString().getString().toString());
+ assertTrue(code.instructions[5] instanceof DexInvokeVirtual);
+ assertTrue(code.instructions[6] instanceof DexReturnVoid);
+ } else {
+ assertTrue(code.instructions[0] instanceof DexConst4);
+ assertTrue(code.instructions[1] instanceof DexNewArray);
+ assertTrue(code.instructions[2] instanceof DexConst4);
+ assertTrue(code.instructions[3] instanceof DexConstClass);
+ assertTrue(code.instructions[4] instanceof DexAputObject);
+ assertTrue(code.instructions[5] instanceof DexConstClass);
+ assertTrue(code.instructions[6] instanceof DexConstString);
+ assertNotEquals("foo", code.instructions[6].asConstString().getString().toString());
+ assertTrue(code.instructions[7] instanceof DexInvokeVirtual);
+ assertTrue(code.instructions[8] instanceof DexReturnVoid);
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index 76bd656..2c99723 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -80,7 +80,11 @@
"java.util.stream.DoubleStream"
+ " java.util.stream.DoubleStream.dropWhile(java.util.function.DoublePredicate)",
// FileStore.getBlockSize() was added in 33 which confuses the required library (30).
- "long java.nio.file.FileStore.getBlockSize()");
+ "long java.nio.file.FileStore.getBlockSize()",
+ // The call is present but unreachable above 26.
+ "java.nio.channels.FileChannel"
+ + " java.nio.channels.DesugarChannels.openEmulatedFileChannel(java.nio.file.Path,"
+ + " java.util.Set, java.nio.file.attribute.FileAttribute[])");
private final TestParameters parameters;
private final CompilationSpecification compilationSpecification;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index a68f3ce..4602235 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -514,8 +514,7 @@
if (clazzType.startsWith("java.")
&& !doesNotNeedWrapper(clazzType, customConversions, maintainType)
// FileChannel is there since B but it needs wrapping due to recently added interfaces.
- && (!preDesugarTypes.contains(clazz)
- || clazzType.equals("java.nio.channels.FileChannel"))) {
+ && !preDesugarTypes.contains(clazz)) {
additions.accept(clazz);
return true;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index 535da2a..5e6c723 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -148,23 +148,23 @@
.streamInstructions()
.filter(instr -> instr.isInvokeInterface() || instr.isInvokeStatic())
.collect(Collectors.toList());
- assertInvokeStaticMatching(invokes, 0, "Set$-EL;->spliterator");
- assertInvokeStaticMatching(invokes, 1, "Collection$-EL;->stream");
- assertInvokeInterfaceMatching(invokes, 2, "Set;->iterator");
- assertInvokeStaticMatching(invokes, 3, "Collection$-EL;->stream");
- assertInvokeStaticMatching(invokes, 4, "Set$-EL;->spliterator");
- assertInvokeInterfaceMatching(invokes, 8, "Iterator;->remove");
- assertInvokeStaticMatching(invokes, 9, "DesugarArrays;->spliterator");
- assertInvokeStaticMatching(invokes, 10, "DesugarArrays;->spliterator");
- assertInvokeStaticMatching(invokes, 11, "DesugarArrays;->stream");
- assertInvokeStaticMatching(invokes, 12, "DesugarArrays;->stream");
- assertInvokeStaticMatching(invokes, 13, "Collection$-EL;->stream");
- assertInvokeStaticMatching(invokes, 14, "IntStream$-CC;->range");
- assertInvokeStaticMatching(invokes, 16, "Comparator$-CC;->comparingInt");
- assertInvokeStaticMatching(invokes, 17, "List$-EL;->sort");
- assertInvokeStaticMatching(invokes, 19, "Comparator$-CC;->comparingInt");
- assertInvokeStaticMatching(invokes, 20, "List$-EL;->sort");
- assertInvokeStaticMatching(invokes, 21, "Collection$-EL;->stream");
+ assertInvokeStaticMatching(invokes, 0, "Set$-EL;spliterator");
+ assertInvokeStaticMatching(invokes, 1, "Collection$-EL;stream");
+ assertInvokeInterfaceMatching(invokes, 2, "Set;iterator");
+ assertInvokeStaticMatching(invokes, 3, "Collection$-EL;stream");
+ assertInvokeStaticMatching(invokes, 4, "Set$-EL;spliterator");
+ assertInvokeInterfaceMatching(invokes, 8, "Iterator;remove");
+ assertInvokeStaticMatching(invokes, 9, "DesugarArrays;spliterator");
+ assertInvokeStaticMatching(invokes, 10, "DesugarArrays;spliterator");
+ assertInvokeStaticMatching(invokes, 11, "DesugarArrays;stream");
+ assertInvokeStaticMatching(invokes, 12, "DesugarArrays;stream");
+ assertInvokeStaticMatching(invokes, 13, "Collection$-EL;stream");
+ assertInvokeStaticMatching(invokes, 14, "IntStream$-CC;range");
+ assertInvokeStaticMatching(invokes, 16, "Comparator$-CC;comparingInt");
+ assertInvokeStaticMatching(invokes, 17, "List$-EL;sort");
+ assertInvokeStaticMatching(invokes, 19, "Comparator$-CC;comparingInt");
+ assertInvokeStaticMatching(invokes, 20, "List$-EL;sort");
+ assertInvokeStaticMatching(invokes, 21, "Collection$-EL;stream");
assertEquals(22, invokes.size());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileChannelTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileChannelTest.java
new file mode 100644
index 0000000..6c5c149
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileChannelTest.java
@@ -0,0 +1,234 @@
+// Copyright (c) 2022, 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.desugar.desugaredlibrary.jdk11;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FileChannelTest extends DesugaredLibraryTestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "true",
+ "true",
+ "true",
+ "true",
+ "Hello World! ",
+ "Hello World! ",
+ "Bye bye. ",
+ "Hello World! ",
+ "Bye bye. ",
+ "Hello World! ",
+ "The monkey eats...",
+ "Bananas!",
+ "Bananas!",
+ "Bananas!");
+
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ // Skip Android 4.4.4 due to missing libjavacrypto.
+ getTestParameters()
+ .withDexRuntime(Version.V4_0_4)
+ .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+ .withAllApiLevels()
+ .build(),
+ ImmutableList.of(JDK11_PATH),
+ DEFAULT_SPECIFICATIONS);
+ }
+
+ public FileChannelTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
+ }
+
+ @Test
+ public void test() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .compile()
+ .withArt6Plus64BitsLib()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) throws IOException {
+ instanceTest();
+ fisTest();
+ fosTest();
+ fileChannelOpen();
+ }
+
+ /**
+ * These check look obvious but they are not on low Api level due to the interface injection.
+ */
+ @SuppressWarnings("all")
+ private static void instanceTest() throws IOException {
+ Path tmp = Files.createTempFile("tmp", ".txt");
+ System.out.println(
+ new FileInputStream(tmp.toFile()).getChannel() instanceof SeekableByteChannel);
+ System.out.println(
+ new FileOutputStream(tmp.toFile()).getChannel() instanceof SeekableByteChannel);
+ System.out.println(
+ new RandomAccessFile(tmp.toFile(), "rw").getChannel() instanceof SeekableByteChannel);
+ System.out.println(
+ Files.newByteChannel(tmp, StandardOpenOption.READ) instanceof SeekableByteChannel);
+ }
+
+ private static void fosTest() throws IOException {
+ String toWrite = "The monkey eats...";
+ Path tmp = Files.createTempFile("fos", ".txt");
+
+ ByteBuffer byteBuffer = ByteBuffer.wrap(toWrite.getBytes(StandardCharsets.UTF_8));
+ FileOutputStream fos = new FileOutputStream(tmp.toFile());
+ FileChannel channel = fos.getChannel();
+ channel.write(byteBuffer);
+
+ List<String> lines = Files.readAllLines(tmp);
+ System.out.println(lines.get(0));
+ }
+
+ private static void fileChannelOpen() throws IOException {
+ fileChannelOpenTest();
+ fileChannelOpenSetTest();
+ fileChannelOpenLockTest();
+ }
+
+ private static void fileChannelOpenLockTest() throws IOException {
+ Path tmp = Files.createTempFile("lock", ".txt");
+ String contents = "Bananas!";
+ Files.write(tmp, contents.getBytes(StandardCharsets.UTF_8));
+ FileChannel fc = FileChannel.open(tmp, StandardOpenOption.READ);
+ ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length());
+ fc.read(byteBuffer);
+ System.out.println(new String(byteBuffer.array()));
+ fc.close();
+ }
+
+ private static void fileChannelOpenTest() throws IOException {
+ Path tmp = Files.createTempFile("a", ".txt");
+ String contents = "Bananas!";
+ Files.write(tmp, contents.getBytes(StandardCharsets.UTF_8));
+ FileChannel fc = FileChannel.open(tmp, StandardOpenOption.READ, StandardOpenOption.WRITE);
+ ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length());
+ // Extra indirection through the lock.
+ fc.lock().channel().read(byteBuffer);
+ System.out.println(new String(byteBuffer.array()));
+ fc.close();
+ }
+
+ private static void fileChannelOpenSetTest() throws IOException {
+ Path tmp = Files.createTempFile("b", ".txt");
+ String contents = "Bananas!";
+ Files.write(tmp, contents.getBytes(StandardCharsets.UTF_8));
+ Set<OpenOption> options = new HashSet<>();
+ options.add(StandardOpenOption.READ);
+ FileChannel fc = FileChannel.open(tmp, options);
+ ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length());
+ fc.read(byteBuffer);
+ System.out.println(new String(byteBuffer.array()));
+ fc.close();
+ }
+
+ private static void fisTest() throws IOException {
+ fisOwner();
+ fisNotOwner(true);
+ fisNotOwner(false);
+ fisOwnerTryResources();
+ }
+
+ private static void fisNotOwner(boolean closeFirst) throws IOException {
+ String toWrite = "Hello World! ";
+ String toWriteFIS = "Bye bye. ";
+ Path tmp = Files.createTempFile("tmp", ".txt");
+ Files.write(tmp, (toWrite + toWriteFIS).getBytes(StandardCharsets.UTF_8));
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(toWrite.length());
+ ByteBuffer byteBufferFIS = ByteBuffer.allocate(toWriteFIS.length());
+ FileInputStream fileInputStream = new FileInputStream(tmp.toFile());
+ FileDescriptor fd = fileInputStream.getFD();
+ FileInputStream fis2 = new FileInputStream(fd);
+ fileInputStream.getChannel().read(byteBuffer);
+ fis2.getChannel().read(byteBufferFIS);
+
+ if (closeFirst) {
+ fileInputStream.close();
+ fis2.close();
+ } else {
+ fis2.close();
+ fileInputStream.close();
+ }
+
+ System.out.println(new String(byteBuffer.array()));
+ System.out.println(new String(byteBufferFIS.array()));
+ }
+
+ private static void fisOwner() throws IOException {
+ String toWrite = "Hello World! ";
+ Path tmp = Files.createTempFile("tmp", ".txt");
+ Files.write(tmp, toWrite.getBytes(StandardCharsets.UTF_8));
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(toWrite.length());
+ FileInputStream fileInputStream = new FileInputStream(tmp.toFile());
+ fileInputStream.getChannel().read(byteBuffer);
+ fileInputStream.close();
+
+ System.out.println(new String(byteBuffer.array()));
+ }
+
+ private static void fisOwnerTryResources() throws IOException {
+ String toWrite = "Hello World! ";
+ Path tmp = Files.createTempFile("tmp", ".txt");
+ Files.write(tmp, toWrite.getBytes(StandardCharsets.UTF_8));
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(toWrite.length());
+ try (FileInputStream fileInputStream = new FileInputStream(tmp.toFile())) {
+ fileInputStream.getChannel().read(byteBuffer);
+ }
+
+ System.out.println(new String(byteBuffer.array()));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
index e6015ad..fb9ca6a 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
@@ -58,21 +58,6 @@
"tmp",
"/",
"true");
- private static final String EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL =
- StringUtils.lines(
- "bytes written: 11",
- "String written: Hello World",
- "bytes read: 11",
- "String read: Hello World",
- "unsupported",
- "unsupported",
- "null",
- "true",
- "unsupported",
- "j$.nio.file.attribute",
- "tmp",
- "/",
- "true");
private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM_DESUGARING =
StringUtils.lines(
"bytes written: 11",
@@ -136,9 +121,7 @@
? EXPECTED_RESULT_PLATFORM_FILE_SYSTEM_DESUGARING
: EXPECTED_RESULT_PLATFORM_FILE_SYSTEM;
}
- return libraryDesugaringSpecification.hasNioChannelDesugaring(parameters)
- ? EXPECTED_RESULT_DESUGARING_FILE_SYSTEM
- : EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL;
+ return EXPECTED_RESULT_DESUGARING_FILE_SYSTEM;
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/JavaTimeJDK11Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/JavaTimeJDK11Test.java
index 09bb322..d6724b5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/JavaTimeJDK11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/JavaTimeJDK11Test.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_LEGACY;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -69,7 +70,7 @@
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- ImmutableList.of(JDK11, JDK11_PATH),
+ ImmutableList.of(JDK11, JDK11_PATH, JDK11_LEGACY),
DEFAULT_SPECIFICATIONS);
}
@@ -101,7 +102,8 @@
.forEach(
i -> {
if (i.isInvoke()) {
- if (libraryDesugaringSpecification.hasTimeDesugaring(parameters)) {
+ if (libraryDesugaringSpecification.hasTimeDesugaring(parameters)
+ && libraryDesugaringSpecification != JDK11_LEGACY) {
checkInvokeTime(i, "j$.time.Duration", "j$.time.LocalTime");
return;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewCollectorsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewCollectorsTest.java
index 4c77e47..84e5f4b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewCollectorsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewCollectorsTest.java
@@ -6,7 +6,9 @@
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_LEGACY;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -46,7 +48,7 @@
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- ImmutableList.of(JDK11, JDK11_PATH),
+ ImmutableList.of(JDK11, JDK11_PATH, JDK11_LEGACY),
DEFAULT_SPECIFICATIONS);
}
@@ -76,7 +78,11 @@
if (libraryDesugaringSpecification.hasEmulatedInterfaceDesugaring(parameters)) {
// Collectors is not present, all calls to the j$ version.
assertTrue(anyStaticInvokeToHolder(methodSubject, "j$.util.stream.Collectors"));
- assertFalse(anyStaticInvokeToHolder(methodSubject, "j$.util.stream.DesugarCollectors"));
+ // In JDK11_LEGACY DesugarCollectors is used whenever possible, in other specifications,
+ // it is used only when needed.
+ assertEquals(
+ libraryDesugaringSpecification == JDK11_LEGACY,
+ anyStaticInvokeToHolder(methodSubject, "j$.util.stream.DesugarCollectors"));
assertFalse(anyStaticInvokeToHolder(methodSubject, "java.util.stream.Collectors"));
return;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
index 1e56f81..7de441c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/r8ondex/R8CompiledThroughDexTest.java
@@ -206,7 +206,7 @@
if (artProcessResult.exitCode != 0) {
System.out.println(artProcessResult);
}
- assertEquals(0, artProcessResult.exitCode);
+ assertEquals(artProcessResult.stderr, 0, artProcessResult.exitCode);
assertProgramsEqual(
"The output of R8/JVM in-process and R8/ART external differ.",
outputThroughCf,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 6245fec..3d76b78 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -37,7 +37,7 @@
public static Descriptor JDK11_DESCRIPTOR = new Descriptor(24, 26, -1, 10000, -1);
public static Descriptor EMPTY_DESCRIPTOR_24 = new Descriptor(-1, -1, -1, 24, -1);
public static Descriptor JDK11_PATH_DESCRIPTOR = new Descriptor(24, 26, 26, 10000, -1);
- public static Descriptor JDK11_LEGACY_DESCRIPTOR = new Descriptor(10000, 10000, -1, 10000, 24);
+ public static Descriptor JDK11_LEGACY_DESCRIPTOR = new Descriptor(24, 26, -1, 32, 24);
private static class Descriptor {
@@ -166,7 +166,7 @@
// The legacy specification is not using the undesugared JAR.
DESUGARED_JDK_11_LIB_JAR,
"jdk11/desugar_jdk_libs_legacy.json",
- AndroidApiLevel.R,
+ AndroidApiLevel.T,
JDK11_LEGACY_DESCRIPTOR,
LEGACY);
public static final LibraryDesugaringSpecification RELEASED_1_0_9 =
diff --git a/src/test/java/com/android/tools/r8/internal/D8Framework14082017VerificationTest.java b/src/test/java/com/android/tools/r8/internal/D8Framework14082017VerificationTest.java
index c8ea9ec..6242204 100644
--- a/src/test/java/com/android/tools/r8/internal/D8Framework14082017VerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/D8Framework14082017VerificationTest.java
@@ -6,11 +6,10 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.VmTestRunner;
-import com.android.tools.r8.VmTestRunner.IgnoreIfVmOlderThan;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Paths;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -20,7 +19,7 @@
private static final String JAR = "third_party/framework/framework_14082017.jar";
@Test
- @IgnoreIfVmOlderThan(Version.V7_0_0)
+ @Ignore("b/259195080")
public void verifyDebugBuild() throws Exception {
runAndCheckVerification(
D8Command.builder()
@@ -32,7 +31,7 @@
}
@Test
- @IgnoreIfVmOlderThan(Version.V7_0_0)
+ @Ignore("b/259195080")
public void verifyReleaseBuild() throws Exception {
runAndCheckVerification(
D8Command.builder()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
index 1e43777..7141ad08 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classmerger/vertical/ArrayPutToInterfaceWithObjectMergingTest.java
@@ -53,8 +53,7 @@
.addProgramClasses(I.class, A.class)
.addProgramClassFileData(getTransformedMain())
.addKeepMainRule(Main.class)
- // Keep get() to prevent that we optimize it into having static return type A.
- .addKeepRules("-keepclassmembers class " + Main.class.getTypeName() + " { *** get(...); }")
+ .addKeepMethodRules(Reference.methodFromMethod(Main.class.getDeclaredMethod("get")))
.addOptionsModification(
options ->
options
diff --git a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
index 0f07d76..d9a6eaf 100644
--- a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
@@ -109,7 +109,7 @@
.addTarget(
target(
buildClassItem(CLASS)
- .setMembersPattern(defaultInitializerPattern())
+ .setMemberPattern(defaultInitializerPattern())
.build()))
.build())
.build();
@@ -146,7 +146,7 @@
.addTarget(
target(
buildClassItem(CLASS)
- .setMembersPattern(defaultInitializerPattern())
+ .setMemberPattern(defaultInitializerPattern())
.build()))
.build())
.build();
@@ -169,7 +169,7 @@
return KeepItemPattern.builder().setClassPattern(KeepQualifiedClassNamePattern.exact(typeName));
}
- private KeepMembersPattern defaultInitializerPattern() {
+ private KeepMemberPattern defaultInitializerPattern() {
return KeepMethodPattern.builder()
.setNamePattern(KeepMethodNamePattern.initializer())
.setParametersPattern(KeepMethodParametersPattern.none())
diff --git a/src/test/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorTest.java b/src/test/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorTest.java
new file mode 100644
index 0000000..94001ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorTest.java
@@ -0,0 +1,63 @@
+// Copyright (c) 2022, 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.keepanno.keeprules;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.keepanno.asm.KeepEdgeReader;
+import com.android.tools.r8.keepanno.ast.KeepEdge;
+import com.android.tools.r8.keepanno.testsource.KeepClassAndDefaultConstructorSource;
+import com.android.tools.r8.keepanno.testsource.KeepSourceEdges;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepRuleExtractorTest extends TestBase {
+
+ private static final Class<?> SOURCE = KeepClassAndDefaultConstructorSource.class;
+ private static final String EXPECTED = KeepSourceEdges.getExpected(SOURCE);
+ private static final Path KEEP_ANNO_PATH =
+ Paths.get(ToolHelper.BUILD_DIR, "classes", "java", "keepanno");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ public KeepRuleExtractorTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ List<String> rules = getKeepRulesForClass(SOURCE);
+ testForR8(parameters.getBackend())
+ .addClasspathFiles(KEEP_ANNO_PATH)
+ .addProgramClassesAndInnerClasses(SOURCE)
+ .addKeepRules(rules)
+ .addKeepMainRule(SOURCE)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), SOURCE)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ private List<String> getKeepRulesForClass(Class<?> clazz) throws IOException {
+ Set<KeepEdge> keepEdges = KeepEdgeReader.readKeepEdges(ToolHelper.getClassAsBytes(clazz));
+ List<String> rules = new ArrayList<>();
+ KeepRuleExtractor extractor = new KeepRuleExtractor(rules::add);
+ keepEdges.forEach(extractor::extract);
+ return rules;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessorTest.java b/src/test/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessorTest.java
index eb7b616..83f60a3 100644
--- a/src/test/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessorTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/processor/KeepEdgeProcessorTest.java
@@ -36,6 +36,7 @@
private static final Path KEEP_ANNO_PATH =
Paths.get(ToolHelper.BUILD_DIR, "classes", "java", "keepanno");
private static final Class<?> SOURCE = KeepClassAndDefaultConstructorSource.class;
+ private static final String EXPECTED = KeepSourceEdges.getExpected(SOURCE);
private final TestParameters parameters;
@@ -63,6 +64,12 @@
checkSynthesizedKeepEdgeClass(inspector, out);
// The source is added as a classpath name but not part of the compilation unit output.
assertThat(inspector.clazz(SOURCE), isAbsent());
+
+ testForJvm()
+ .addProgramClasses(SOURCE, KeepClassAndDefaultConstructorSource.A.class)
+ .addProgramFiles(out)
+ .run(parameters.getRuntime(), SOURCE)
+ .assertSuccessWithOutput(EXPECTED);
}
@Test
@@ -78,7 +85,7 @@
testForJvm()
.addProgramFiles(out)
.run(parameters.getRuntime(), SOURCE)
- .assertSuccessWithOutputLines("A is alive!")
+ .assertSuccessWithOutput(EXPECTED)
.inspect(
inspector -> {
assertThat(inspector.clazz(SOURCE), isPresent());
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java
index ca83a46..b9fb2b6 100644
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java
+++ b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java
@@ -9,9 +9,11 @@
@KeepEdge(
consequences = {
// Keep the class to allow lookup of it.
- @KeepTarget(classConstant = KeepClassAndDefaultConstructorSource.class),
+ @KeepTarget(classConstant = KeepClassAndDefaultConstructorSource.A.class),
// Keep the default constructor.
- @KeepTarget(classConstant = KeepClassAndDefaultConstructorSource.class, methodName = "<init>")
+ @KeepTarget(
+ classConstant = KeepClassAndDefaultConstructorSource.A.class,
+ methodName = "<init>")
})
public class KeepClassAndDefaultConstructorSource {
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
index b6369de..5637edf 100644
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
+++ b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.KeepTarget;
+import com.android.tools.r8.utils.StringUtils;
import java.util.Collections;
import java.util.Set;
@@ -27,8 +28,19 @@
throw new RuntimeException();
}
+ public static String getExpected(Class<?> clazz) {
+ if (clazz.equals(KeepClassAndDefaultConstructorSource.class)) {
+ return getKeepClassAndDefaultConstructorSourceExpected();
+ }
+ throw new RuntimeException();
+ }
+
+ public static String getKeepClassAndDefaultConstructorSourceExpected() {
+ return StringUtils.lines("A is alive!");
+ }
+
public static Set<KeepEdge> getKeepClassAndDefaultConstructorSourceEdges() {
- Class<?> clazz = KeepClassAndDefaultConstructorSource.class;
+ Class<?> clazz = KeepClassAndDefaultConstructorSource.A.class;
// Build the class target.
KeepQualifiedClassNamePattern name = KeepQualifiedClassNamePattern.exact(clazz.getTypeName());
KeepItemPattern classItem = KeepItemPattern.builder().setClassPattern(name).build();
@@ -37,10 +49,7 @@
KeepMethodPattern constructorMethod =
KeepMethodPattern.builder().setNamePattern(KeepMethodNamePattern.exact("<init>")).build();
KeepItemPattern constructorItem =
- KeepItemPattern.builder()
- .setClassPattern(name)
- .setMembersPattern(constructorMethod)
- .build();
+ KeepItemPattern.builder().setClassPattern(name).setMemberPattern(constructorMethod).build();
KeepTarget constructorTarget = KeepTarget.builder().setItem(constructorItem).build();
// The consequet set is the class an its constructor.
KeepConsequences consequences =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index 9fd2a2e..87dc848 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -133,9 +133,7 @@
if (kotlinParameters.isNewerThan(KOTLINC_1_7_0)) {
assertThat(
compileResult.stderr,
- containsString(
- "the feature \"references to synthetic java properties\" is only available since"
- + " language version 1.9"));
+ containsString("the feature \"references to synthetic java properties\""));
} else {
assertThat(
compileResult.stderr,
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
index 83ea780..c544c9e 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
@@ -16,10 +16,12 @@
import com.android.tools.r8.dex.code.DexConst4;
import com.android.tools.r8.dex.code.DexConstClass;
import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
import com.android.tools.r8.dex.code.DexInvokeDirect;
import com.android.tools.r8.dex.code.DexInvokeStatic;
import com.android.tools.r8.dex.code.DexInvokeVirtual;
import com.android.tools.r8.dex.code.DexIputObject;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
import com.android.tools.r8.dex.code.DexNewArray;
import com.android.tools.r8.dex.code.DexReturnVoid;
import com.android.tools.r8.dex.code.DexSgetObject;
@@ -639,7 +641,8 @@
+ "}",
"-keep class " + CLASS_NAME,
"-keep class R { *; }");
- CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
+ CodeInspector inspector =
+ compileWithR8(builder, testBuilder -> testBuilder.addKeepRules(pgConfigs)).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
assertTrue(clazz.isPresent());
@@ -647,19 +650,33 @@
assertNotNull(method);
DexCode code = method.getCode().asDexCode();
- checkInstructions(
- code,
- ImmutableList.of(
- DexInvokeDirect.class,
- DexConst4.class,
- DexNewArray.class,
- DexConst4.class,
- DexConstClass.class,
- DexAputObject.class,
- DexConstString.class,
- DexInvokeStatic.class,
- DexReturnVoid.class));
- DexConstString constString = (DexConstString) code.instructions[6];
+ // Accept either array construction style (differs based on minSdkVersion).
+ if (code.instructions[2].getClass() == DexFilledNewArray.class) {
+ checkInstructions(
+ code,
+ ImmutableList.of(
+ DexInvokeDirect.class,
+ DexConstClass.class,
+ DexFilledNewArray.class,
+ DexMoveResultObject.class,
+ DexConstString.class,
+ DexInvokeStatic.class,
+ DexReturnVoid.class));
+ } else {
+ checkInstructions(
+ code,
+ ImmutableList.of(
+ DexInvokeDirect.class,
+ DexConst4.class,
+ DexNewArray.class,
+ DexConst4.class,
+ DexConstClass.class,
+ DexAputObject.class,
+ DexConstString.class,
+ DexInvokeStatic.class,
+ DexReturnVoid.class));
+ }
+ DexConstString constString = (DexConstString) code.instructions[code.instructions.length - 3];
assertEquals("foo", constString.getString().toString());
}
@@ -700,7 +717,8 @@
+ "}",
"-keep class " + CLASS_NAME,
"-keep,allowobfuscation class R { *; }");
- CodeInspector inspector = compileWithR8(builder, pgConfigs).inspector();
+ CodeInspector inspector =
+ compileWithR8(builder, testBuilder -> testBuilder.addKeepRules(pgConfigs)).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
assertTrue(clazz.isPresent());
@@ -708,19 +726,33 @@
assertNotNull(method);
DexCode code = method.getCode().asDexCode();
- checkInstructions(
- code,
- ImmutableList.of(
- DexInvokeDirect.class,
- DexConst4.class,
- DexNewArray.class,
- DexConst4.class,
- DexConstClass.class,
- DexAputObject.class,
- DexConstString.class,
- DexInvokeStatic.class,
- DexReturnVoid.class));
- DexConstString constString = (DexConstString) code.instructions[6];
+ // Accept either array construction style (differs based on minSdkVersion).
+ if (code.instructions[2].getClass() == DexFilledNewArray.class) {
+ checkInstructions(
+ code,
+ ImmutableList.of(
+ DexInvokeDirect.class,
+ DexConstClass.class,
+ DexFilledNewArray.class,
+ DexMoveResultObject.class,
+ DexConstString.class,
+ DexInvokeStatic.class,
+ DexReturnVoid.class));
+ } else {
+ checkInstructions(
+ code,
+ ImmutableList.of(
+ DexInvokeDirect.class,
+ DexConst4.class,
+ DexNewArray.class,
+ DexConst4.class,
+ DexConstClass.class,
+ DexAputObject.class,
+ DexConstString.class,
+ DexInvokeStatic.class,
+ DexReturnVoid.class));
+ }
+ DexConstString constString = (DexConstString) code.instructions[code.instructions.length - 3];
assertNotEquals("foo", constString.getString().toString());
}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java
new file mode 100644
index 0000000..3b7a115
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java
@@ -0,0 +1,111 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoMethodStaticizing;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationDestinationOverrideLibraryTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private static final String[] EXPECTED = new String[] {"LibraryMethod421337"};
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, ProgramClass.class, X.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryClasses(LibraryClass.class)
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/258720808): We should not fail compilation.
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class, ProgramClass.class, X.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryClasses(LibraryClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addDontObfuscate()
+ .enableInliningAnnotations()
+ .enableNoMethodStaticizingAnnotations()
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorMessageThatMatches(
+ containsString(
+ "went from not overriding a library method to overriding a library"
+ + " method"));
+ }));
+ }
+
+ public static class LibraryClass {
+
+ public void foo(int i1, int i2, String bar) {
+ System.out.println(bar + i1 + i2);
+ }
+
+ public static void callFoo(LibraryClass clazz) {
+ clazz.foo(42, 1337, "LibraryMethod");
+ }
+ }
+
+ public static class ProgramClass extends LibraryClass {
+ @NeverInline
+ @NoMethodStaticizing
+ public void foo(String bar, int i1, int i2) {
+ System.out.println(i1 + i2 + bar);
+ }
+ }
+
+ // Needs to have a class name that is after lexicographically than ProgramClass.
+ public static class X {
+ @NeverInline
+ public void foo(int i1, String bar, int i2) {
+ System.out.println(i1 + bar + i2);
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ ProgramClass programClass = new ProgramClass();
+ X otherProgramClass = new X();
+ if (args.length == 1) {
+ programClass.foo("Hello World", 1, 1);
+ otherProgramClass.foo(1, "Hello World", 1);
+ } else if (args.length > 1) {
+ programClass.foo("Goodbye World", 2, 2);
+ otherProgramClass.foo(2, "Goodbye World", 2);
+ }
+ LibraryClass.callFoo(programClass);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
index ba776e4..c179493 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
@@ -33,6 +33,20 @@
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
+ private final String[] EXPECTED =
+ new String[] {"A::foo", "B", "A", "B::foo", "B", "A", "B::foo", "B", "A"};
+
+ private final String[] R8_EXPECTED =
+ new String[] {"A::foo", "B", "A", "A::foo", "B", "A", "B::foo", "B", "A"};
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
@@ -40,20 +54,23 @@
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
- // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
.addDontObfuscate()
+ .addKeepClassAndMembersRules(B.class)
.setMinApi(parameters.getApiLevel())
.compile()
+ .run(parameters.getRuntime(), Main.class)
+ // TODO(b/258720808): We should not produce incorrect results.
+ .assertSuccessWithOutputLines(R8_EXPECTED)
.inspect(
inspector -> {
- ClassSubject aClassSubject = inspector.clazz(A.class);
- assertThat(aClassSubject, isPresent());
-
ClassSubject bClassSubject = inspector.clazz(B.class);
assertThat(bClassSubject, isPresent());
- TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+ TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithOriginalName("foo");
assertThat(fooMethodSubject, isPresent());
@@ -62,12 +79,10 @@
// TODO(b/173398086): Consider rewriting B.foo(B, A) to B.foo(A, B, C) instead of
// B.foo$1(A, B).
MethodSubject otherFooMethodSubject =
- bClassSubject.uniqueMethodWithOriginalName("foo$1");
+ bClassSubject.uniqueMethodWithOriginalName("foo");
assertThat(otherFooMethodSubject, isPresent());
assertThat(otherFooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
- })
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A", "B", "A", "B");
+ });
}
static class Main {
@@ -75,16 +90,18 @@
public static void main(String[] args) {
A a = new A();
B b = new B();
+ a.foo(b, a);
a.foo(a, b);
- b.foo(b, a);
+ b.foo(a, b);
}
}
@NoVerticalClassMerging
- static class A {
+ static class B {
@NeverInline
public void foo(A a, B b) {
+ System.out.println("B::foo");
System.out.println(a);
System.out.println(b);
}
@@ -95,10 +112,11 @@
}
}
- static class B extends A {
+ static class A extends B {
@NeverInline
public void foo(B b, A a) {
+ System.out.println("A::foo");
System.out.println(a);
System.out.println(b);
}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
index c233d49..e665c12 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
@@ -41,7 +41,8 @@
RetracePartitionRoundTripTest.ApiTest.class,
RetracePartitionJoinNoMetadataTest.ApiTest.class,
RetracePartitionSerializedObfuscatedKeyTest.ApiTest.class,
- RetracePartitionRoundTripInlineTest.ApiTest.class);
+ RetracePartitionRoundTripInlineTest.ApiTest.class,
+ RetraceApiTypeResultTest.ApiTest.class);
public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
ImmutableList.of(RetraceApiResidualSignatureTest.ApiTest.class);
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTypeResultTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTypeResultTest.java
new file mode 100644
index 0000000..4d76e2c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTypeResultTest.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2022, 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.retrace.api;
+
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceTypeElement;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiTypeResultTest extends RetraceApiTestBase {
+
+ public RetraceApiTypeResultTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ public static class ApiTest implements RetraceApiBinaryTest {
+
+ private final TypeReference minifiedName = Reference.typeFromTypeName("a[]");
+ private final TypeReference original = Reference.typeFromTypeName("some.Class[]");
+
+ private static final String mapping =
+ "# { id: 'com.android.tools.r8.mapping', version: '1.0' }\nsome.Class -> a:\n";
+
+ @Test
+ public void testRetraceClassArray() {
+ List<RetraceTypeElement> collect =
+ Retracer.createDefault(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
+ .retraceType(minifiedName)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, collect.size());
+ assertEquals(original, collect.get(0).getType().getTypeReference());
+ }
+
+ @Test
+ public void testRetracePrimitiveArray() {
+ TypeReference intArr = Reference.typeFromTypeName("int[][]");
+ List<RetraceTypeElement> collect =
+ Retracer.createDefault(
+ ProguardMapProducer.fromString(mapping), new DiagnosticsHandler() {})
+ .retraceType(intArr)
+ .stream()
+ .collect(Collectors.toList());
+ assertEquals(1, collect.size());
+ assertEquals(intArr, collect.get(0).getType().getTypeReference());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
index 4a76a6a..513dc73 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.graph.AppView;
@@ -15,6 +16,7 @@
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -33,7 +35,7 @@
this.parameters = parameters;
}
- private static final String[] expectedOutput = {"3"};
+ private static final String[] expectedOutput = {"3", "2"};
@Test
public void d8() throws Exception {
@@ -44,7 +46,7 @@
.addOptionsModification(opt -> opt.testing.irModifier = this::transformArray)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(expectedOutput)
- .inspect(this::assertNoArrayLength);
+ .inspect(i -> inspect(i, true));
}
@Test
@@ -54,32 +56,52 @@
.addProgramClasses(Main.class)
.addOptionsModification(opt -> opt.testing.irModifier = this::transformArray)
.addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(expectedOutput)
- .inspect(this::assertNoArrayLength);
+ .inspect(i -> inspect(i, false));
}
private void transformArray(IRCode irCode, AppView<?> appView) {
- if (irCode.context().getReference().getName().toString().contains("main")) {
new CodeRewriter(appView).simplifyArrayConstruction(irCode);
+ String name = irCode.context().getReference().getName().toString();
+ if (name.contains("filledArrayData")) {
assertTrue(irCode.streamInstructions().anyMatch(Instruction::isNewArrayFilledData));
+ } else if (name.contains("filledNewArray")) {
+ assertTrue(irCode.streamInstructions().anyMatch(Instruction::isInvokeNewArray));
}
}
- private void assertNoArrayLength(CodeInspector inspector) {
+ private void inspect(CodeInspector inspector, boolean d8) {
ClassSubject mainClass = inspector.clazz(Main.class);
assertTrue(mainClass.isPresent());
- assertTrue(
- mainClass.mainMethod().streamInstructions().noneMatch(InstructionSubject::isArrayLength));
+ MethodSubject filledArrayData = mainClass.uniqueMethodWithOriginalName("filledArrayData");
+ assertTrue(filledArrayData.streamInstructions().noneMatch(InstructionSubject::isArrayLength));
+ if (!d8) {
+ MethodSubject filledNewArray = mainClass.uniqueMethodWithOriginalName("filledNewArray");
+ assertTrue(filledNewArray.streamInstructions().noneMatch(InstructionSubject::isArrayLength));
+ }
}
public static final class Main {
+ @NeverInline
+ public static void filledArrayData() {
+ short[] values = new short[3];
+ values[0] = 5;
+ values[1] = 6;
+ values[2] = 1;
+ System.out.println(values.length);
+ }
+
+ @NeverInline
+ public static void filledNewArray() {
+ int[] values = new int[] {7, 8};
+ System.out.println(values.length);
+ }
+
public static void main(String[] args) {
- int[] ints = new int[3];
- ints[0] = 5;
- ints[1] = 6;
- ints[2] = 1;
- System.out.println(ints.length);
+ filledArrayData();
+ filledNewArray();
}
}
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
new file mode 100644
index 0000000..939753f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
@@ -0,0 +1,774 @@
+// Copyright (c) 2022, 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.rewrite.arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.dex.code.DexFillArrayData;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
+import com.android.tools.r8.dex.code.DexFilledNewArrayRange;
+import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.beust.jcommander.internal.Lists;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SimplifyArrayConstructionTest extends TestBase {
+ @Parameters(name = "{0}, mode = {1}")
+ public static Iterable<?> data() {
+ return buildParameters(
+ getTestParameters().withDefaultCfRuntime().withDexRuntimesAndAllApiLevels().build(),
+ CompilationMode.values());
+ }
+
+ private final TestParameters parameters;
+ private final CompilationMode compilationMode;
+
+ public SimplifyArrayConstructionTest(TestParameters parameters, CompilationMode compilationMode) {
+ this.parameters = parameters;
+ this.compilationMode = compilationMode;
+ }
+
+ private static final Class<?>[] DEX_ARRAY_INSTRUCTIONS = {
+ DexNewArray.class, DexFilledNewArray.class, DexFilledNewArrayRange.class, DexFillArrayData.class
+ };
+
+ private static final String[] EXPECTED_OUTPUT = {
+ "[a]",
+ "[a, 1, null]",
+ "[1, null]",
+ "[1, null, 2]",
+ "[1, null, 2]",
+ "[1]",
+ "[1, 2]",
+ "[1, 2, 3, 4, 5]",
+ "[1]",
+ "[a, 1, null, d, e, f]",
+ "[1, null, 3, null, null, 6]",
+ "[1, 2, 3, 4, 5, 6]",
+ "[true, false]",
+ "[1, 2]",
+ "[1, 2]",
+ "[1, 2]",
+ "[1.0, 2.0]",
+ "[1.0, 2.0]",
+ "[]",
+ "[]",
+ "[true]",
+ "[1]",
+ "[1]",
+ "[1]",
+ "[1.0]",
+ "[1.0]",
+ "[0, 1]",
+ "[1, null]",
+ "[a]",
+ "[0, 1]",
+ "200",
+ "[0, 1, 2, 3, 4]",
+ "[4, 0, 0, 0, 0]",
+ "[4, 1, 2, 3, 4]",
+ "[0, 1, 2]",
+ "[0]",
+ "[0, 1, 2]",
+ "[1, 2, 3]",
+ "[1, 2, 3, 4, 5, 6]",
+ "[0]",
+ "[null, null]",
+ };
+
+ private static final byte[] TRANSFORMED_MAIN = transformedMain();
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeFalse(compilationMode == CompilationMode.DEBUG);
+ testForRuntime(
+ parameters.getRuntime(),
+ d8TestBuilder ->
+ d8TestBuilder.setMinApi(parameters.getApiLevel()).setMode(compilationMode))
+ .addProgramClassFileData(TRANSFORMED_MAIN)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED_OUTPUT)
+ .inspect(inspector -> inspect(inspector, false));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(Serializable.class)))
+ .setMode(compilationMode)
+ .addProgramClassFileData(TRANSFORMED_MAIN)
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .addKeepAnnotation()
+ .addKeepRules("-keepclassmembers class * { @com.android.tools.r8.Keep *; }")
+ .addKeepRules("-assumenosideeffects class * { *** assumedNullField return null; }")
+ .addKeepRules("-assumenosideeffects class * { *** assumedNonNullField return _NONNULL_; }")
+ .addDontObfuscate()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED_OUTPUT)
+ .inspect(inspector -> inspect(inspector, true));
+ }
+
+ private static byte[] transformedMain() {
+ try {
+ return transformer(Main.class)
+ .transformMethodInsnInMethod(
+ "interfaceArrayWithRawObject",
+ (opcode, owner, name, descriptor, isInterface, visitor) -> {
+ if (name.equals("getObjectThatImplementsSerializable")) {
+ visitor.visitMethodInsn(opcode, owner, name, "()Ljava/lang/Object;", isInterface);
+ } else {
+ visitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ })
+ .setReturnType(
+ ClassFileTransformer.MethodPredicate.onName("getObjectThatImplementsSerializable"),
+ Object.class.getTypeName())
+ .transform();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void inspect(CodeInspector inspector, boolean isR8) {
+ if (parameters.isCfRuntime()) {
+ return;
+ }
+ ClassSubject mainClass = inspector.clazz(Main.class);
+ assertTrue(mainClass.isPresent());
+
+ MethodSubject stringArrays = mainClass.uniqueMethodWithOriginalName("stringArrays");
+ MethodSubject referenceArraysNoCasts =
+ mainClass.uniqueMethodWithOriginalName("referenceArraysNoCasts");
+ MethodSubject referenceArraysWithSubclasses =
+ mainClass.uniqueMethodWithOriginalName("referenceArraysWithSubclasses");
+ MethodSubject interfaceArrayWithRawObject =
+ mainClass.uniqueMethodWithOriginalName("interfaceArrayWithRawObject");
+
+ MethodSubject phiFilledNewArray = mainClass.uniqueMethodWithOriginalName("phiFilledNewArray");
+ MethodSubject intsThatUseFilledNewArray =
+ mainClass.uniqueMethodWithOriginalName("intsThatUseFilledNewArray");
+ MethodSubject twoDimensionalArrays =
+ mainClass.uniqueMethodWithOriginalName("twoDimensionalArrays");
+ MethodSubject objectArraysFilledNewArrayRange =
+ mainClass.uniqueMethodWithOriginalName("objectArraysFilledNewArrayRange");
+ MethodSubject arraysThatUseFilledData =
+ mainClass.uniqueMethodWithOriginalName("arraysThatUseFilledData");
+ MethodSubject arraysThatUseNewArrayEmpty =
+ mainClass.uniqueMethodWithOriginalName("arraysThatUseNewArrayEmpty");
+ MethodSubject reversedArray = mainClass.uniqueMethodWithOriginalName("reversedArray");
+ MethodSubject arrayWithCorrectCountButIncompleteCoverage =
+ mainClass.uniqueMethodWithOriginalName("arrayWithCorrectCountButIncompleteCoverage");
+ MethodSubject arrayWithExtraInitialPuts =
+ mainClass.uniqueMethodWithOriginalName("arrayWithExtraInitialPuts");
+ MethodSubject catchHandlerThrowing =
+ mainClass.uniqueMethodWithOriginalName("catchHandlerThrowing");
+ MethodSubject catchHandlerNonThrowingFilledNewArray =
+ mainClass.uniqueMethodWithOriginalName("catchHandlerNonThrowingFilledNewArray");
+ MethodSubject catchHandlerNonThrowingFillArrayData =
+ mainClass.uniqueMethodWithOriginalName("catchHandlerNonThrowingFillArrayData");
+ MethodSubject assumedValues = mainClass.uniqueMethodWithOriginalName("assumedValues");
+
+ assertArrayTypes(arraysThatUseNewArrayEmpty, DexNewArray.class);
+ assertArrayTypes(intsThatUseFilledNewArray, DexFilledNewArray.class);
+ assertFilledArrayData(arraysThatUseFilledData);
+
+ if (compilationMode == CompilationMode.DEBUG) {
+ // The explicit assignments can't be collapsed without breaking the debugger's ability to
+ // visit each line.
+ assertArrayTypes(reversedArray, DexNewArray.class);
+ } else {
+ assertArrayTypes(reversedArray, DexFilledNewArray.class);
+ }
+
+ // Cannot use filled-new-array of String before K.
+ if (parameters.getApiLevel().isLessThan(AndroidApiLevel.K)) {
+ assertArrayTypes(stringArrays, DexNewArray.class);
+ } else {
+ assertArrayTypes(stringArrays, DexFilledNewArray.class);
+ }
+ // Cannot use filled-new-array of Object before L.
+ if (parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
+ assertArrayTypes(referenceArraysNoCasts, DexNewArray.class);
+ assertArrayTypes(referenceArraysWithSubclasses, DexNewArray.class);
+ assertArrayTypes(phiFilledNewArray, DexNewArray.class);
+ assertArrayTypes(objectArraysFilledNewArrayRange, DexNewArray.class);
+ assertArrayTypes(twoDimensionalArrays, DexNewArray.class);
+ assertArrayTypes(assumedValues, DexNewArray.class);
+ } else {
+ assertArrayTypes(referenceArraysNoCasts, DexFilledNewArray.class);
+ // TODO(b/246971330): Add support for arrays with subtypes.
+ if (isR8) {
+ assertArrayTypes(referenceArraysWithSubclasses, DexFilledNewArray.class);
+ } else {
+ assertArrayTypes(referenceArraysWithSubclasses, DexNewArray.class);
+ }
+
+ // TODO(b/246971330): Add support for arrays whose values have conditionals.
+ // assertArrayTypes(phiFilledNewArray, DexFilledNewArray.class);
+
+ assertArrayTypes(objectArraysFilledNewArrayRange, DexFilledNewArrayRange.class);
+
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
+ assertArrayTypes(twoDimensionalArrays, DexFilledNewArray.class);
+ } else {
+ // No need to assert this case. If it's wrong, Dalvik verify errors cause test failures.
+ }
+
+ assertArrayTypes(assumedValues, DexFilledNewArray.class);
+ }
+ // filled-new-array fails verification when types of parameters are not subclasses (aput-object
+ // does not).
+ assertArrayTypes(interfaceArrayWithRawObject, DexNewArray.class);
+
+ // These could be optimized to use InvokeNewArray, but they seem like rare code patterns so we
+ // haven't bothered.
+ assertArrayTypes(arrayWithExtraInitialPuts, DexNewArray.class);
+ assertArrayTypes(arrayWithCorrectCountButIncompleteCoverage, DexNewArray.class);
+
+ assertArrayTypes(catchHandlerThrowing, DexNewArray.class);
+ assertArrayTypes(catchHandlerNonThrowingFillArrayData, DexNewArray.class);
+ assertArrayTypes(catchHandlerNonThrowingFilledNewArray, DexFilledNewArray.class);
+ }
+
+ private static Predicate<InstructionSubject> isInstruction(List<Class<?>> allowlist) {
+ return (ins) -> allowlist.contains(ins.asDexInstruction().getInstruction().getClass());
+ }
+
+ private static Predicate<InstructionSubject> isInstruction(Class<?> clazz) {
+ return isInstruction(Arrays.asList(clazz));
+ }
+
+ private static void assertArrayTypes(MethodSubject method, Class<?> allowedArrayInst) {
+ assertTrue(method.isPresent());
+ List<Class<?>> disallowedClasses = Lists.newArrayList(DEX_ARRAY_INSTRUCTIONS);
+ disallowedClasses.remove(allowedArrayInst);
+
+ assertTrue(method.streamInstructions().anyMatch(isInstruction(allowedArrayInst)));
+ assertTrue(method.streamInstructions().noneMatch(isInstruction(disallowedClasses)));
+ }
+
+ private static void assertFilledArrayData(MethodSubject method) {
+ assertTrue(method.isPresent());
+ List<Class<?>> disallowedClasses = Lists.newArrayList(DEX_ARRAY_INSTRUCTIONS);
+ disallowedClasses.remove(DexFillArrayData.class);
+ disallowedClasses.remove(DexNewArray.class);
+
+ assertTrue(method.streamInstructions().noneMatch(isInstruction(disallowedClasses)));
+ assertTrue(method.streamInstructions().noneMatch(InstructionSubject::isArrayPut));
+ long numNewArray = method.streamInstructions().filter(InstructionSubject::isNewArray).count();
+ long numFillArray =
+ method.streamInstructions().filter(isInstruction(DexFillArrayData.class)).count();
+ assertEquals(numNewArray, numFillArray);
+ }
+
+ public static final class Main {
+ static final String assumedNonNullField = null;
+ static final String assumedNullField = null;
+
+ public static void main(String[] args) {
+ stringArrays();
+ referenceArraysNoCasts();
+ referenceArraysWithSubclasses();
+ interfaceArrayWithRawObject();
+ phiFilledNewArray();
+ intsThatUseFilledNewArray();
+ twoDimensionalArrays();
+ objectArraysFilledNewArrayRange();
+ arraysThatUseFilledData();
+ arraysThatUseNewArrayEmpty();
+ reversedArray();
+ arrayWithCorrectCountButIncompleteCoverage();
+ arrayWithExtraInitialPuts();
+ catchHandlerThrowing();
+ catchHandlerNonThrowingFilledNewArray();
+ catchHandlerNonThrowingFillArrayData();
+ arrayIntoAnotherArray();
+ assumedValues();
+ }
+
+ @NeverInline
+ private static void stringArrays() {
+ // Test exact class, no null.
+ String[] stringArr = {"a"};
+ System.out.println(Arrays.toString(stringArr));
+ }
+
+ @NeverInline
+ private static void referenceArraysNoCasts() {
+ // Tests that no type info is needed when array type is Object[].
+ Object[] objectArr = {"a", 1, null};
+ System.out.println(Arrays.toString(objectArr));
+ // Test that interface arrays work when we have the exact interface already.
+ Serializable[] interfaceArr = {getSerializable(1), null};
+ System.out.println(Arrays.toString(interfaceArr));
+ }
+
+ @Keep
+ private static Serializable getSerializable(Integer value) {
+ return value;
+ }
+
+ @NeverInline
+ private static void referenceArraysWithSubclasses() {
+ Serializable[] interfaceArr = {1, null, 2};
+ System.out.println(Arrays.toString(interfaceArr));
+ Number[] objArray = {1, null, 2};
+ System.out.println(Arrays.toString(objArray));
+ }
+
+ @NeverInline
+ private static void interfaceArrayWithRawObject() {
+ // Interfaces can use filled-new-array only when we know types implement the interface.
+ Serializable[] arr = new Serializable[1];
+ // Transformed from `I get()` to `Object get()`.
+ arr[0] = getObjectThatImplementsSerializable();
+ System.out.println(Arrays.toString(arr));
+ }
+
+ @Keep
+ private static /*Object*/ Serializable getObjectThatImplementsSerializable() {
+ return 1;
+ }
+
+ @NeverInline
+ private static void reversedArray() {
+ int[] arr = new int[5];
+ arr[4] = 4;
+ arr[3] = 3;
+ arr[2] = 2;
+ arr[1] = 1;
+ arr[0] = 0;
+ System.out.println(Arrays.toString(arr));
+ }
+
+ @NeverInline
+ private static void arrayWithCorrectCountButIncompleteCoverage() {
+ int[] arr = new int[5];
+ arr[0] = 0;
+ arr[0] = 1;
+ arr[0] = 2;
+ arr[0] = 3;
+ arr[0] = 4;
+ System.out.println(Arrays.toString(arr));
+ }
+
+ @NeverInline
+ private static void arrayWithExtraInitialPuts() {
+ int[] arr = new int[5];
+ arr[0] = 0;
+ arr[0] = 1;
+ arr[0] = 2;
+ arr[0] = 3;
+ arr[0] = 4;
+ arr[1] = 1;
+ arr[2] = 2;
+ arr[3] = 3;
+ arr[4] = 4;
+ System.out.println(Arrays.toString(arr));
+ }
+
+ @NeverInline
+ private static void catchHandlerNonThrowingFilledNewArray() {
+ try {
+ int[] arr1 = {1, 2, 3};
+ System.currentTimeMillis();
+ System.out.println(Arrays.toString(arr1));
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @NeverInline
+ private static void catchHandlerNonThrowingFillArrayData() {
+ try {
+ int[] arr = {1, 2, 3, 4, 5, 6};
+ System.currentTimeMillis();
+ System.out.println(Arrays.toString(arr));
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @NeverInline
+ private static void catchHandlerThrowing() {
+ int[] arr1 = new int[3];
+ arr1[0] = 0;
+ arr1[1] = 1;
+ // Since the array is used in only one spot, and that spot is not within the try/catch, it
+ // should be safe to use filled-new-array, but we don't.
+ try {
+ System.currentTimeMillis();
+ arr1[2] = 2;
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ System.out.println(Arrays.toString(arr1));
+
+ try {
+ // Test filled-new-array with a throwing instruction before the last array-put.
+ int[] arr2 = new int[1];
+ System.currentTimeMillis();
+ arr2[0] = 0;
+ System.out.println(Arrays.toString(arr2));
+
+ // Test filled-array-data with a throwing instruction before the last array-put.
+ short[] arr3 = new short[3];
+ arr3[0] = 0;
+ arr3[1] = 1;
+ System.currentTimeMillis();
+ arr3[2] = 2;
+ System.out.println(Arrays.toString(arr3));
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @NeverInline
+ private static void arrayIntoAnotherArray() {
+ // Tests that our computeValues() method does not assume all array-put-object users have
+ // the array as the target.
+ int[] intArr = new int[1];
+ Object[] objArr = new Object[2];
+ objArr[0] = intArr;
+ System.out.println(Arrays.toString((int[]) objArr[0]));
+ }
+
+ @NeverInline
+ private static void assumedValues() {
+ Object[] arr = {assumedNonNullField, assumedNullField};
+ System.out.println(Arrays.toString(arr));
+ }
+
+ @NeverInline
+ private static void phiFilledNewArray() {
+ // The presence of ? should not affect use of filled-new-array.
+ Integer[] phiArray = {1, System.nanoTime() > 0 ? 2 : 3};
+ System.out.println(Arrays.toString(phiArray));
+ }
+
+ @NeverInline
+ private static void intsThatUseFilledNewArray() {
+ // Up to 5 ints uses filled-new-array rather than filled-array-data.
+ int[] intArr = {1, 2, 3, 4, 5};
+ System.out.println(Arrays.toString(intArr));
+ }
+
+ @NeverInline
+ private static void twoDimensionalArrays() {
+ Integer[][] twoDimensions = {new Integer[] {1}, null};
+ System.out.println(Arrays.toString(Arrays.asList(twoDimensions).get(0)));
+ }
+
+ @NeverInline
+ private static void objectArraysFilledNewArrayRange() {
+ // 6 or more elements use /range variant.
+ Object[] objectArr = {"a", 1, null, "d", "e", "f"};
+ System.out.println(Arrays.toString(objectArr));
+ Serializable[] interfaceArr = {
+ getSerializable(1), null, getSerializable(3), null, null, getSerializable(6)
+ };
+ System.out.println(Arrays.toString(interfaceArr));
+ }
+
+ @NeverInline
+ private static void arraysThatUseFilledData() {
+ // For int[], <= 5 elements should use NewArrayFilledData (otherwise NewFilledArray is used).
+ int[] intArr = {1, 2, 3, 4, 5, 6};
+ // For other primitives, > 1 element leads to fill-array-data.
+ System.out.println(Arrays.toString(intArr));
+ boolean[] boolArr = {true, false};
+ System.out.println(Arrays.toString(boolArr));
+ byte[] byteArr = {1, 2};
+ System.out.println(Arrays.toString(byteArr));
+ char[] charArr = {'1', '2'};
+ System.out.println(Arrays.toString(charArr));
+ long[] longArr = {1, 2};
+ System.out.println(Arrays.toString(longArr));
+ float[] floatArr = {1, 2};
+ System.out.println(Arrays.toString(floatArr));
+ double[] doubleArr = {1, 2};
+ System.out.println(Arrays.toString(doubleArr));
+ }
+
+ @NeverInline
+ private static void arraysThatUseNewArrayEmpty() {
+ // int/object of size zero should not use filled-new-array.
+ int[] intArr = {};
+ System.out.println(Arrays.toString(intArr));
+ String[] strArr = {};
+ System.out.println(Arrays.toString(strArr));
+
+ // Other primitives with size <= 1 should not use filled-array-data.
+ boolean[] boolArr = {true};
+ System.out.println(Arrays.toString(boolArr));
+ byte[] byteArr = {1};
+ System.out.println(Arrays.toString(byteArr));
+ char[] charArr = {'1'};
+ System.out.println(Arrays.toString(charArr));
+ long[] longArr = {1};
+ System.out.println(Arrays.toString(longArr));
+ float[] floatArr = {1};
+ System.out.println(Arrays.toString(floatArr));
+ double[] doubleArr = {1};
+ System.out.println(Arrays.toString(doubleArr));
+
+ // Array used before all members are set.
+ int[] readArray = new int[2];
+ readArray[0] = (int) (System.currentTimeMillis() / System.nanoTime());
+ readArray[1] = readArray[0] + 1;
+ System.out.println(Arrays.toString(readArray));
+
+ // Array does not have all elements set (we could make this work, but likely this is rare).
+ Integer[] partialArray = new Integer[2];
+ partialArray[0] = 1;
+ System.out.println(Arrays.toString(partialArray));
+
+ // Non-constant array size.
+ int trickyZero = (int) (System.currentTimeMillis() / System.nanoTime());
+ Object[] nonConstSize = new Object[trickyZero + 1];
+ nonConstSize[0] = "a";
+ System.out.println(Arrays.toString(nonConstSize));
+
+ // Non-constant index.
+ Object[] nonConstIndex = new Object[2];
+ nonConstIndex[trickyZero] = 0;
+ nonConstIndex[trickyZero + 1] = 1;
+ System.out.println(Arrays.toString(nonConstIndex));
+
+ // Exceeds our (arbitrary) size limit for /range.
+ String[] bigArr = new String[201];
+ bigArr[0] = "0";
+ bigArr[1] = "1";
+ bigArr[2] = "2";
+ bigArr[3] = "3";
+ bigArr[4] = "4";
+ bigArr[5] = "5";
+ bigArr[6] = "6";
+ bigArr[7] = "7";
+ bigArr[8] = "8";
+ bigArr[9] = "9";
+ bigArr[10] = "10";
+ bigArr[11] = "11";
+ bigArr[12] = "12";
+ bigArr[13] = "13";
+ bigArr[14] = "14";
+ bigArr[15] = "15";
+ bigArr[16] = "16";
+ bigArr[17] = "17";
+ bigArr[18] = "18";
+ bigArr[19] = "19";
+ bigArr[20] = "20";
+ bigArr[21] = "21";
+ bigArr[22] = "22";
+ bigArr[23] = "23";
+ bigArr[24] = "24";
+ bigArr[25] = "25";
+ bigArr[26] = "26";
+ bigArr[27] = "27";
+ bigArr[28] = "28";
+ bigArr[29] = "29";
+ bigArr[30] = "30";
+ bigArr[31] = "31";
+ bigArr[32] = "32";
+ bigArr[33] = "33";
+ bigArr[34] = "34";
+ bigArr[35] = "35";
+ bigArr[36] = "36";
+ bigArr[37] = "37";
+ bigArr[38] = "38";
+ bigArr[39] = "39";
+ bigArr[40] = "40";
+ bigArr[41] = "41";
+ bigArr[42] = "42";
+ bigArr[43] = "43";
+ bigArr[44] = "44";
+ bigArr[45] = "45";
+ bigArr[46] = "46";
+ bigArr[47] = "47";
+ bigArr[48] = "48";
+ bigArr[49] = "49";
+ bigArr[50] = "50";
+ bigArr[51] = "51";
+ bigArr[52] = "52";
+ bigArr[53] = "53";
+ bigArr[54] = "54";
+ bigArr[55] = "55";
+ bigArr[56] = "56";
+ bigArr[57] = "57";
+ bigArr[58] = "58";
+ bigArr[59] = "59";
+ bigArr[60] = "60";
+ bigArr[61] = "61";
+ bigArr[62] = "62";
+ bigArr[63] = "63";
+ bigArr[64] = "64";
+ bigArr[65] = "65";
+ bigArr[66] = "66";
+ bigArr[67] = "67";
+ bigArr[68] = "68";
+ bigArr[69] = "69";
+ bigArr[70] = "70";
+ bigArr[71] = "71";
+ bigArr[72] = "72";
+ bigArr[73] = "73";
+ bigArr[74] = "74";
+ bigArr[75] = "75";
+ bigArr[76] = "76";
+ bigArr[77] = "77";
+ bigArr[78] = "78";
+ bigArr[79] = "79";
+ bigArr[80] = "80";
+ bigArr[81] = "81";
+ bigArr[82] = "82";
+ bigArr[83] = "83";
+ bigArr[84] = "84";
+ bigArr[85] = "85";
+ bigArr[86] = "86";
+ bigArr[87] = "87";
+ bigArr[88] = "88";
+ bigArr[89] = "89";
+ bigArr[90] = "90";
+ bigArr[91] = "91";
+ bigArr[92] = "92";
+ bigArr[93] = "93";
+ bigArr[94] = "94";
+ bigArr[95] = "95";
+ bigArr[96] = "96";
+ bigArr[97] = "97";
+ bigArr[98] = "98";
+ bigArr[99] = "99";
+ bigArr[100] = "100";
+ bigArr[101] = "101";
+ bigArr[102] = "102";
+ bigArr[103] = "103";
+ bigArr[104] = "104";
+ bigArr[105] = "105";
+ bigArr[106] = "106";
+ bigArr[107] = "107";
+ bigArr[108] = "108";
+ bigArr[109] = "109";
+ bigArr[110] = "110";
+ bigArr[111] = "111";
+ bigArr[112] = "112";
+ bigArr[113] = "113";
+ bigArr[114] = "114";
+ bigArr[115] = "115";
+ bigArr[116] = "116";
+ bigArr[117] = "117";
+ bigArr[118] = "118";
+ bigArr[119] = "119";
+ bigArr[120] = "120";
+ bigArr[121] = "121";
+ bigArr[122] = "122";
+ bigArr[123] = "123";
+ bigArr[124] = "124";
+ bigArr[125] = "125";
+ bigArr[126] = "126";
+ bigArr[127] = "127";
+ bigArr[128] = "128";
+ bigArr[129] = "129";
+ bigArr[130] = "130";
+ bigArr[131] = "131";
+ bigArr[132] = "132";
+ bigArr[133] = "133";
+ bigArr[134] = "134";
+ bigArr[135] = "135";
+ bigArr[136] = "136";
+ bigArr[137] = "137";
+ bigArr[138] = "138";
+ bigArr[139] = "139";
+ bigArr[140] = "140";
+ bigArr[141] = "141";
+ bigArr[142] = "142";
+ bigArr[143] = "143";
+ bigArr[144] = "144";
+ bigArr[145] = "145";
+ bigArr[146] = "146";
+ bigArr[147] = "147";
+ bigArr[148] = "148";
+ bigArr[149] = "149";
+ bigArr[150] = "150";
+ bigArr[151] = "151";
+ bigArr[152] = "152";
+ bigArr[153] = "153";
+ bigArr[154] = "154";
+ bigArr[155] = "155";
+ bigArr[156] = "156";
+ bigArr[157] = "157";
+ bigArr[158] = "158";
+ bigArr[159] = "159";
+ bigArr[160] = "160";
+ bigArr[161] = "161";
+ bigArr[162] = "162";
+ bigArr[163] = "163";
+ bigArr[164] = "164";
+ bigArr[165] = "165";
+ bigArr[166] = "166";
+ bigArr[167] = "167";
+ bigArr[168] = "168";
+ bigArr[169] = "169";
+ bigArr[170] = "170";
+ bigArr[171] = "171";
+ bigArr[172] = "172";
+ bigArr[173] = "173";
+ bigArr[174] = "174";
+ bigArr[175] = "175";
+ bigArr[176] = "176";
+ bigArr[177] = "177";
+ bigArr[178] = "178";
+ bigArr[179] = "179";
+ bigArr[180] = "180";
+ bigArr[181] = "181";
+ bigArr[182] = "182";
+ bigArr[183] = "183";
+ bigArr[184] = "184";
+ bigArr[185] = "185";
+ bigArr[186] = "186";
+ bigArr[187] = "187";
+ bigArr[188] = "188";
+ bigArr[189] = "189";
+ bigArr[190] = "190";
+ bigArr[191] = "191";
+ bigArr[192] = "192";
+ bigArr[193] = "193";
+ bigArr[194] = "194";
+ bigArr[195] = "195";
+ bigArr[196] = "196";
+ bigArr[197] = "197";
+ bigArr[198] = "198";
+ bigArr[199] = "199";
+ bigArr[200] = "200";
+ System.out.println(Arrays.asList(bigArr).get(200));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideDefaultMethodTest.java b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideDefaultMethodTest.java
new file mode 100644
index 0000000..939b14a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideDefaultMethodTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2022, 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.shaking.librarymethodoverride;
+
+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.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.Enqueuer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LibraryMethodOverrideDefaultMethodTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(ProgramI.class, ProgramClass.class, Main.class)
+ .addLibraryClasses(LibraryI.class, LibraryClass.class)
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, LibraryI.class, LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("ProgramI::foo");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(ProgramI.class, ProgramClass.class, Main.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addOptionsModification(
+ options -> options.testing.enqueuerInspector = this::verifyLibraryOverrideInformation)
+ .addLibraryClasses(LibraryI.class, LibraryClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .compile()
+ .addBootClasspathClasses(LibraryI.class, LibraryClass.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("ProgramI::foo");
+ }
+
+ private void verifyLibraryOverrideInformation(AppInfoWithLiveness appInfo, Enqueuer.Mode mode) {
+ DexItemFactory dexItemFactory = appInfo.dexItemFactory();
+ DexProgramClass clazz =
+ appInfo
+ .definitionFor(dexItemFactory.createType(descriptor(ProgramI.class)))
+ .asProgramClass();
+ DexEncodedMethod method =
+ clazz.lookupVirtualMethod(m -> m.getReference().name.toString().equals("foo"));
+ assertTrue(method.isLibraryMethodOverride().isTrue());
+ }
+
+ public interface LibraryI {
+
+ void foo();
+ }
+
+ public static class LibraryClass {
+
+ public static void callI(LibraryI i) {
+ i.foo();
+ }
+ }
+
+ public interface ProgramI extends LibraryI {
+
+ @Override
+ default void foo() {
+ System.out.println("ProgramI::foo");
+ }
+ }
+
+ public static class ProgramClass implements ProgramI {}
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ LibraryClass.callI(new ProgramClass());
+ }
+ }
+}
diff --git a/third_party/retrace/binary_compatibility.tar.gz.sha1 b/third_party/retrace/binary_compatibility.tar.gz.sha1
index 023f1c9..e86ba01 100644
--- a/third_party/retrace/binary_compatibility.tar.gz.sha1
+++ b/third_party/retrace/binary_compatibility.tar.gz.sha1
@@ -1 +1 @@
-ec4f1b68e126b5b5e8a53078c74c79c65e190cf2
\ No newline at end of file
+8eea4fa493bb7cb63d11e8d2a0ac34775726825e
\ No newline at end of file
diff --git a/tools/archive_desugar_jdk_libs.py b/tools/archive_desugar_jdk_libs.py
index 63d02c6..08f453e 100755
--- a/tools/archive_desugar_jdk_libs.py
+++ b/tools/archive_desugar_jdk_libs.py
@@ -140,12 +140,31 @@
+ github_account + '/' + GITHUB_REPRO, checkout_dir)
git_utils.GitCheckout(desugar_jdk_libs_hash, checkout_dir)
-def GetJavaEnv():
+def GetJavaEnv(androidHomeTemp):
java_env = dict(os.environ, JAVA_HOME = jdk.GetJdk11Home())
java_env['PATH'] = java_env['PATH'] + os.pathsep + os.path.join(jdk.GetJdk11Home(), 'bin')
java_env['GRADLE_OPTS'] = '-Xmx1g'
+ java_env['ANDROID_HOME'] = androidHomeTemp
return java_env
+def setUpFakeAndroidHome(androidHomeTemp):
+ # Bazel will check if 30 is present then extract android.jar from 32.
+ # We copy android.jar from third_party to mimic repository structure.
+ subpath = os.path.join(androidHomeTemp, "platforms")
+ cmd = ["mkdir", subpath]
+ subprocess.check_call(cmd)
+ subpath30 = os.path.join(subpath, "android-30")
+ cmd = ["mkdir", subpath30]
+ subprocess.check_call(cmd)
+ subpath = os.path.join(subpath, "android-32")
+ cmd = ["mkdir", subpath]
+ subprocess.check_call(cmd)
+ dest = os.path.join(subpath, "android.jar")
+ sha = os.path.join(utils.THIRD_PARTY, "android_jar", "lib-v32.tar.gz.sha1")
+ utils.DownloadFromGoogleCloudStorage(sha)
+ src = os.path.join(utils.THIRD_PARTY, "android_jar", "lib-v32", "android.jar")
+ cmd = ["cp", src, dest]
+ subprocess.check_call(cmd)
def BuildDesugaredLibrary(checkout_dir, variant, version = None):
if not variant in MAVEN_RELEASE_TARGET_MAP:
@@ -153,19 +172,22 @@
if variant != 'jdk8' and variant != 'jdk11_legacy' and version is None:
raise Exception('Variant ' + variant + ' require version for undesugaring')
with utils.ChangedWorkingDirectory(checkout_dir):
- bazel = os.path.join(utils.BAZEL_TOOL, 'lib', 'bazel', 'bin', 'bazel')
- cmd = [
+ with utils.TempDir() as androidHomeTemp:
+ setUpFakeAndroidHome(androidHomeTemp)
+ javaEnv = GetJavaEnv(androidHomeTemp)
+ bazel = os.path.join(utils.BAZEL_TOOL, 'lib', 'bazel', 'bin', 'bazel')
+ cmd = [
bazel,
'--bazelrc=/dev/null',
'build',
'--spawn_strategy=local',
'--verbose_failures',
MAVEN_RELEASE_TARGET_MAP[variant]]
- utils.PrintCmd(cmd)
- subprocess.check_call(cmd, env=GetJavaEnv())
- cmd = [bazel, 'shutdown']
- utils.PrintCmd(cmd)
- subprocess.check_call(cmd, env=GetJavaEnv())
+ utils.PrintCmd(cmd)
+ subprocess.check_call(cmd, env=javaEnv)
+ cmd = [bazel, 'shutdown']
+ utils.PrintCmd(cmd)
+ subprocess.check_call(cmd, env=javaEnv)
# Locate the library jar and the maven zip with the jar from the
# bazel build.
diff --git a/tools/dex2oat.py b/tools/dex2oat.py
index 04422cf..10c4732 100755
--- a/tools/dex2oat.py
+++ b/tools/dex2oat.py
@@ -12,16 +12,21 @@
LINUX_DIR = os.path.join(utils.TOOLS_DIR, 'linux')
+LATEST = '12.0.0'
+
VERSIONS = [
- 'default',
- '9.0.0',
- '8.1.0',
- '7.0.0',
+ '12.0.0',
+ # TODO(b/258170524): Fix the broken dex2oat versions.
+ # 'default',
+ # '9.0.0',
+ # '8.1.0',
+ # '7.0.0',
'6.0.1',
- '5.1.1',
+ # '5.1.1',
]
DIRS = {
+ '12.0.0': 'host/art-12.0.0-beta4',
'default': 'art',
'9.0.0': 'art-9.0.0',
'8.1.0': 'art-8.1.0',
@@ -31,6 +36,7 @@
}
PRODUCTS = {
+ '12.0.0': 'redfin',
'default': 'angler',
'9.0.0': 'marlin',
'8.1.0': 'marlin',
@@ -40,6 +46,7 @@
}
ARCHS = {
+ '12.0.0': 'x86_64',
'default': 'arm64',
'9.0.0': 'arm64',
'8.1.0': 'arm64',
@@ -58,12 +65,16 @@
'all',
]
+BOOT_IMAGE = {
+ '12.0.0': 'apex/art_boot_images/javalib/boot.art'
+}
+
def ParseOptions():
parser = optparse.OptionParser()
parser.add_option('--version',
- help='Version of dex2oat. (defaults to latest, eg, tools/linux/art).',
+ help='Version of dex2oat. (defaults to latest: ' + LATEST + ').',
choices=VERSIONS,
- default='default')
+ default=LATEST)
parser.add_option('--all',
help='Run dex2oat on all possible versions',
default=False,
@@ -96,7 +107,9 @@
print("")
return 0
-def run(dexfile, oatfile=None, version='default', verbose=[]):
+def run(dexfile, oatfile=None, version=None, verbose=[]):
+ if not version:
+ version = LATEST
# dex2oat accepts non-existent dex files, check here instead
if not os.path.exists(dexfile):
raise Exception('DEX file not found: "{}"'.format(dexfile))
@@ -117,9 +130,12 @@
]
for flag in verbose:
cmd += ['--runtime-arg', '-verbose:' + flag]
+ if version in BOOT_IMAGE:
+ cmd += ['--boot-image=' + BOOT_IMAGE[version]]
env = {"LD_LIBRARY_PATH": os.path.join(base, 'lib')}
utils.PrintCmd(cmd)
- subprocess.check_call(cmd, env = env)
+ with utils.ChangedWorkingDirectory(base):
+ subprocess.check_call(cmd, env = env)
if __name__ == '__main__':
sys.exit(Main())
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
index 5e38ebd..611c06e 100644
--- a/tools/linux/README.art-versions
+++ b/tools/linux/README.art-versions
@@ -115,6 +115,10 @@
--art-dir host/art-12.0.0-beta4 \
--android-product redfin
+The dex2oat tool expects to find core-oj.dex in out/host/linux-x86 so copy it.
+
+(cd tools/linux/host; cp -r apex out/host/linux-x86/apex)
+
(cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-12.0.0-beta4)
art-10.0.0 (Android Q)
diff --git a/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1 b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
index b95d909..9f80774 100644
--- a/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
+++ b/tools/linux/host/art-12.0.0-beta4.tar.gz.sha1
@@ -1 +1 @@
-9b6d0b061669e0fb1b09ba92c3650d5c7bdc9e85
\ No newline at end of file
+df7267e9eff9cc1812b5a7b4111e7175d5e186e9
\ No newline at end of file