Merge "Virtualize some methods from TypeLatticeElement"
diff --git a/build.gradle b/build.gradle
index e6432e4..580bcaf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -478,13 +478,16 @@
}
}
-static configureRelocations(ShadowJar task) {
+static mergeServiceFiles(ShadowJar task) {
// Everything under META-INF is not included by default.
// Should include before 'relocate' so that the service file path and its content
// are properly relocated as well.
task.mergeServiceFiles {
include 'META-INF/services/*'
}
+}
+
+static configureRelocations(ShadowJar task) {
task.relocate('com.google.common', 'com.android.tools.r8.com.google.common')
task.relocate('com.google.gson', 'com.android.tools.r8.com.google.gson')
task.relocate('com.google.thirdparty', 'com.android.tools.r8.com.google.thirdparty')
@@ -500,7 +503,10 @@
task repackageDeps(type: ShadowJar) {
configurations = [project.configurations.compile]
- configureRelocations(it)
+ mergeServiceFiles(it)
+ if (!project.hasProperty('lib_no_relocate')) {
+ configureRelocations(it)
+ }
exclude { it.getRelativePath().getPathString() == "module-info.class" }
exclude { it.getRelativePath().getPathString().startsWith("META-INF/maven/") }
baseName 'deps'
@@ -508,7 +514,10 @@
task repackageSources(type: ShadowJar) {
from sourceSets.main.output
- configureRelocations(it)
+ mergeServiceFiles(it)
+ if (!project.hasProperty('lib_no_relocate')) {
+ configureRelocations(it)
+ }
baseName 'sources'
}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 96e1e99..7b24770 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -650,6 +650,9 @@
assert internal.enableVerticalClassMerging || !proguardConfiguration.isOptimizing();
if (internal.debug) {
+ internal.proguardConfiguration.getKeepAttributes().lineNumberTable = true;
+ internal.proguardConfiguration.getKeepAttributes().localVariableTable = true;
+ internal.proguardConfiguration.getKeepAttributes().localVariableTypeTable = true;
// TODO(zerny): Should we support inlining in debug mode? b/62937285
internal.enableInlining = false;
internal.enableClassInlining = false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 3df31fd..22790b4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -412,6 +412,10 @@
return null;
}
+ public boolean isExternalizable(AppInfo appInfo) {
+ return type.implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.externalizableType);
+ }
+
public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
return Arrays.stream(staticFields())
.anyMatch(field -> !field.getStaticValue().mayTriggerAllocation());
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index fa856cb..6c6fda4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -206,7 +206,10 @@
if (localsChanged()) {
assert emittedPc != pc;
int pcDelta = emittedPc == NO_PC_INFO ? pc : pc - emittedPc;
- events.add(factory.createAdvancePC(pcDelta));
+ assert pcDelta > 0 || emittedPc == NO_PC_INFO;
+ if (pcDelta > 0) {
+ events.add(factory.createAdvancePC(pcDelta));
+ }
emittedPc = pc;
emitLocalChangeEvents(emittedLocals, pendingLocals, lastKnownLocals, events, factory);
pendingLocalChanges = false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 7254577..90a098a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -256,6 +256,7 @@
public final DexType callSiteType = createType("Ljava/lang/invoke/CallSite;");
public final DexType lookupType = createType("Ljava/lang/invoke/MethodHandles$Lookup;");
public final DexType serializableType = createType("Ljava/io/Serializable;");
+ public final DexType externalizableType = createType("Ljava/io/Externalizable;");
public final DexType comparableType = createType("Ljava/lang/Comparable;");
public final DexMethod metafactoryMethod =
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 fe63f46..138e07e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -37,6 +37,9 @@
*/
private Set<DexType> directSubtypes = NO_DIRECT_SUBTYPE;
+ // Caching what interfaces this type is implementing. This includes super-interface hierarchy.
+ private Set<DexType> implementedInterfaces;
+
DexType(DexString descriptor) {
assert !descriptor.toString().contains(".");
this.descriptor = descriptor;
@@ -234,9 +237,12 @@
* @return a set of interfaces of {@link DexType}.
*/
public Set<DexType> implementedInterfaces(AppInfo appInfo) {
- Set<DexType> interfaces = Sets.newIdentityHashSet();
- implementedInterfaces(appInfo, interfaces);
- return interfaces;
+ if (implementedInterfaces == null) {
+ Set<DexType> interfaces = Sets.newIdentityHashSet();
+ implementedInterfaces(appInfo, interfaces);
+ implementedInterfaces = interfaces;
+ }
+ return implementedInterfaces;
}
private void implementedInterfaces(AppInfo appInfo, Set<DexType> interfaces) {
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 bfb2b95..de42c18 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -265,13 +265,18 @@
if (item.isDexClass()) {
DexClass clazz = item.asDexClass();
workList.add(Action.markInstantiated(clazz, reason));
- if (forceProguardCompatibility && clazz.hasDefaultInitializer()) {
- ProguardKeepRule compatRule =
+ if (clazz.hasDefaultInitializer()) {
+ if (forceProguardCompatibility) {
+ ProguardKeepRule compatRule =
ProguardConfigurationUtils.buildDefaultInitializerKeepRule(clazz);
- proguardCompatibilityWorkList.add(
- Action.markMethodLive(
- clazz.getDefaultInitializer(),
- KeepReason.dueToProguardCompatibilityKeepRule(compatRule)));
+ proguardCompatibilityWorkList.add(
+ Action.markMethodLive(
+ clazz.getDefaultInitializer(),
+ KeepReason.dueToProguardCompatibilityKeepRule(compatRule)));
+ }
+ if (clazz.isExternalizable(appInfo)) {
+ workList.add(Action.markMethodLive(clazz.getDefaultInitializer(), reason));
+ }
}
} else if (item.isDexEncodedField()) {
workList.add(Action.markFieldKept(item.asDexEncodedField(), reason));
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index e7351f2..08a220f 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -456,7 +456,7 @@
DexType collection = factory.createType("Ljava/util/Collection;");
DexType set = factory.createType("Ljava/util/Set;");
DexType list = factory.createType("Ljava/util/List;");
- DexType serializable = factory.createType("Ljava/io/Serializable;");
+ DexType serializable = factory.serializableType;
Set<DexType> lub = computeLeastUpperBoundOfInterfaces(appInfo,
ImmutableSet.of(set), ImmutableSet.of(list));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
index 1eddbd3..d7a5732 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/checkcast/CheckCastDebugTestRunner.java
@@ -29,6 +29,7 @@
import java.util.Arrays;
import java.util.Collection;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -76,6 +77,7 @@
assertThat(classSubject, isPresent());
}
+ @Ignore("todo: jsjeon")
@Test
public void test_differentLocals() throws Throwable {
ClassSubject classSubject = inspector.clazz(MAIN);
@@ -129,6 +131,7 @@
);
}
+ @Ignore("todo: jsjeon")
@Test
public void test_sameLocal() throws Throwable {
ClassSubject classSubject = inspector.clazz(MAIN);
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
index 275d2e9..96ce54a 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAttributesTest.java
@@ -3,33 +3,57 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.debuginfo.DebugInfoInspector;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes.TestKeepAttributes;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
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 KeepAttributesTest extends TestBase {
- public static final Class CLASS = TestKeepAttributes.class;
+ private static final Class CLASS = TestKeepAttributes.class;
+
+ @Parameters(name = "{0}")
+ public static Backend[] parameters() {
+ return new Backend[] { Backend.CF, Backend.DEX};
+ }
+
+ private final Backend backend;
+
+ public KeepAttributesTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void keepAllAttributesInDebugMode()
+ throws ExecutionException, CompilationFailedException, IOException {
+ List<String> keepRules = ImmutableList.of(
+ "-keep class ** { *; }"
+ );
+ MethodSubject mainMethod = compileRunAndGetMain(keepRules, CompilationMode.DEBUG);
+ assertTrue(mainMethod.hasLineNumberTable());
+ assertTrue(mainMethod.hasLocalVariableTable());
+ }
@Test
public void discardAllAttributes()
@@ -37,10 +61,9 @@
List<String> keepRules = ImmutableList.of(
"-keep class ** { *; }"
);
- CodeInspector inspector = compile(keepRules);
- DebugInfoInspector debugInfo = debugInfoForMain(inspector);
- checkLineNumbers(false, debugInfo);
- checkLocals(false, debugInfo);
+ MethodSubject mainMethod = compileRunAndGetMain(keepRules, CompilationMode.RELEASE);
+ assertFalse(mainMethod.hasLineNumberTable());
+ assertFalse(mainMethod.hasLocalVariableTable());
}
@Test
@@ -50,10 +73,9 @@
"-keep class ** { *; }",
"-keepattributes " + ProguardKeepAttributes.LINE_NUMBER_TABLE
);
- CodeInspector inspector = compile(keepRules);
- DebugInfoInspector debugInfo = debugInfoForMain(inspector);
- checkLineNumbers(true, debugInfo);
- checkLocals(false, debugInfo);
+ MethodSubject mainMethod = compileRunAndGetMain(keepRules, CompilationMode.RELEASE);
+ assertTrue(mainMethod.hasLineNumberTable());
+ assertFalse(mainMethod.hasLocalVariableTable());
}
@Test
@@ -66,10 +88,10 @@
+ ", "
+ ProguardKeepAttributes.LOCAL_VARIABLE_TABLE
);
- CodeInspector inspector = compile(keepRules);
- DebugInfoInspector debugInfo = debugInfoForMain(inspector);
- checkLineNumbers(true, debugInfo);
- checkLocals(true, debugInfo);
+ MethodSubject mainMethod = compileRunAndGetMain(keepRules, CompilationMode.RELEASE);
+ assertTrue(mainMethod.hasLineNumberTable());
+ // Locals are never included in release builds.
+ assertFalse(mainMethod.hasLocalVariableTable());
}
@Test
@@ -80,7 +102,7 @@
);
// Compiling with a keep rule for locals but no line results in an error in R8.
try {
- compile(keepRules);
+ compileRunAndGetMain(keepRules, CompilationMode.RELEASE);
} catch (CompilationFailedException e) {
assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LOCAL_VARIABLE_TABLE));
assertTrue(e.getCause().getMessage().contains(ProguardKeepAttributes.LINE_NUMBER_TABLE));
@@ -89,34 +111,23 @@
fail("Expected error");
}
- private CodeInspector compile(List<String> keepRules)
+ private MethodSubject compileRunAndGetMain(List<String> keepRules, CompilationMode mode)
throws CompilationFailedException, IOException, ExecutionException {
- Path dexOut = temp.getRoot().toPath().resolve("dex.zip");
- R8.run(R8Command.builder()
- .setMode(CompilationMode.DEBUG)
- .addProgramFiles(ToolHelper.getClassFileForTestClass(CLASS))
- .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
- .addProguardConfiguration(keepRules, Origin.unknown())
- .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(dexOut))
- .build());
- ToolHelper.runArtRaw(dexOut.toString(), CLASS.getCanonicalName());
- return new CodeInspector(dexOut);
+ AndroidAppConsumers sink = new AndroidAppConsumers();
+ R8.run(
+ R8Command.builder()
+ .setMode(mode)
+ .addProgramFiles(
+ ToolHelper.getClassFilesForTestDirectory(
+ ToolHelper.getClassFileForTestClass(CLASS).getParent()))
+ .addLibraryFiles(runtimeJar(backend))
+ .addProguardConfiguration(keepRules, Origin.unknown())
+ .setProgramConsumer(sink.wrapProgramConsumer(emptyConsumer(backend)))
+ .build());
+ AndroidApp app = sink.build();
+ CodeInspector codeInspector = new CodeInspector(app);
+ runOnVM(app, CLASS.getTypeName(), backend);
+ return codeInspector.clazz(CLASS).mainMethod();
}
- private DebugInfoInspector debugInfoForMain(CodeInspector inspector) {
- return new DebugInfoInspector(
- inspector,
- CLASS.getCanonicalName(),
- new MethodSignature("main", "void", Collections.singleton("java.lang.String[]")));
- }
-
- private void checkLineNumbers(boolean expected, DebugInfoInspector debugInfo) {
- assertEquals("Expected " + (expected ? "line entries" : "no line entries"),
- expected, debugInfo.getEntries().stream().anyMatch(e -> e.lineEntry));
- }
-
- private void checkLocals(boolean expected, DebugInfoInspector debugInfo) {
- assertEquals("Expected " + (expected ? "locals" : "no locals"),
- expected, debugInfo.getEntries().stream().anyMatch(e -> !e.locals.isEmpty()));
- }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
index 952bae6..cf14d8b 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
@@ -88,13 +88,13 @@
case PROGUARD6_THEN_D8:
return runProguard6AndD8(programClasses, proguardConfig, proguardMap);
case R8_COMPAT:
- return runR8Compat(programClasses, proguardConfig, Backend.DEX);
+ return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.DEX);
case R8_COMPAT_CF:
- return runR8Compat(programClasses, proguardConfig, Backend.CF);
+ return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.CF);
case R8:
- return runR8(programClasses, proguardConfig, Backend.DEX);
+ return runR8(programClasses, proguardConfig, proguardMap, Backend.DEX);
case R8_CF:
- return runR8(programClasses, proguardConfig, Backend.CF);
+ return runR8(programClasses, proguardConfig, proguardMap, Backend.CF);
}
throw new IllegalArgumentException("Unknown shrinker: " + mode);
}
@@ -126,34 +126,45 @@
throw new IllegalArgumentException("Unknown shrinker: " + mode);
}
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses,
+ String proguardConfig,
+ Path proguardMap,
+ Backend backend)
throws Exception {
- return runR8(programClasses, proguardConfig, null, backend);
+ return runR8(programClasses, proguardConfig, proguardMap, null, backend);
}
protected AndroidApp runR8(
List<Class> programClasses,
String proguardConfig,
+ Path proguardMap,
Consumer<InternalOptions> configure,
Backend backend)
throws Exception {
AndroidApp app = readClassesAndRuntimeJar(programClasses, backend);
R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app, emptyConsumer(backend));
ToolHelper.allowTestProguardOptions(builder);
- builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
+ builder.addProguardConfiguration(
+ ImmutableList.of(proguardConfig, toPrintMappingRule(proguardMap)), Origin.unknown());
return ToolHelper.runR8(builder.build(), configure);
}
protected CodeInspector inspectR8Result(
List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
- return new CodeInspector(runR8(programClasses, proguardConfig, backend));
+ return new CodeInspector(runR8(programClasses, proguardConfig, null, backend));
}
protected AndroidApp runR8Compat(
- List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
+ List<Class> programClasses,
+ String proguardConfig,
+ Path proguardMap,
+ Backend backend)
+ throws Exception {
CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder(true);
ToolHelper.allowTestProguardOptions(builder);
- builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
+ builder.addProguardConfiguration(
+ ImmutableList.of(proguardConfig, toPrintMappingRule(proguardMap)), Origin.unknown());
programClasses.forEach(
clazz -> builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz)));
if (backend == Backend.DEX) {
@@ -169,7 +180,7 @@
protected CodeInspector inspectR8CompatResult(
List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
- return new CodeInspector(runR8Compat(programClasses, proguardConfig, backend));
+ return new CodeInspector(runR8Compat(programClasses, proguardConfig, null, backend));
}
protected AndroidApp runProguard5(
@@ -306,4 +317,8 @@
assertThat(c, not(isPresent()));
}
}
+
+ private String toPrintMappingRule(Path proguardMap) {
+ return proguardMap == null ? "" : "-printmapping " + proguardMap.toAbsolutePath();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
index dcb1970c..e20b80a 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
@@ -264,7 +264,9 @@
@Parameterized.Parameters(name = "Shrinker: {0}")
public static Collection<Object> data() {
return ImmutableList.of(
- Shrinker.PROGUARD6_THEN_D8, Shrinker.PROGUARD6, Shrinker.R8, Shrinker.R8_CF);
+ Shrinker.PROGUARD6_THEN_D8, Shrinker.PROGUARD6,
+ Shrinker.R8_COMPAT, Shrinker.R8_COMPAT_CF,
+ Shrinker.R8, Shrinker.R8_CF);
}
public ExternalizableTest(Shrinker shrinker) {
@@ -273,11 +275,6 @@
@Test
public void testExternalizable() throws Exception {
- // TODO(b/116735204): R8 should keep default ctor() of classes that implement Externalizable
- if (shrinker.isR8()) {
- return;
- }
-
String javaOutput = runOnJava(ExternalizableTestMain.class);
List<String> config = ImmutableList.of(
@@ -300,6 +297,12 @@
assertEquals(javaOutput.trim(), output.trim());
}
+ // https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serial-arch.html
+ // 1.11 The Externalizable Interface
+ // ...
+ // The class of an Externalizable object must do the following:
+ // ...
+ // * Have a public no-arg constructor
CodeInspector codeInspector = new CodeInspector(processedApp, proguardMap);
ClassSubject classSubject = codeInspector.clazz(ExternalizableDataClass.class);
assertThat(classSubject, isPresent());
@@ -336,6 +339,12 @@
assertEquals(javaOutput.trim(), output.trim());
}
+ // https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serial-arch.html
+ // 1.10 The Serializable Interface
+ // ...
+ // A Serializable class must do the following:
+ // ...
+ // * Have access to the no-arg constructor of its first non-serializable superclass
CodeInspector codeInspector = new CodeInspector(processedApp, proguardMap);
ClassSubject classSubject = codeInspector.clazz(NonSerializableSuperClass.class);
assertThat(classSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index 5ea7769..89d5079 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@@ -45,10 +46,12 @@
}
@Override
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
throws Exception {
// Disable inlining, otherwise classes can be pruned away if all their methods are inlined.
- return runR8(programClasses, proguardConfig, o -> o.enableInlining = false, backend);
+ return runR8(
+ programClasses, proguardConfig, proguardMap, o -> o.enableInlining = false, backend);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index b003b7b..165a68f 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -89,9 +89,10 @@
}
@Override
- protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+ protected AndroidApp runR8(
+ List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
throws Exception {
- return super.runR8(programClasses, proguardConfig, this::configure, backend);
+ return super.runR8(programClasses, proguardConfig, proguardMap, this::configure, backend);
}
private void check(AndroidApp app) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 1396be9..adee8cf 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -78,4 +78,14 @@
public String getFinalSignatureAttribute() {
return null;
}
+
+ @Override
+ public boolean hasLineNumberTable() {
+ return false;
+ }
+
+ @Override
+ public boolean hasLocalVariableTable() {
+ return false;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 3fe8186..f205594 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,12 +4,22 @@
package com.android.tools.r8.utils.codeinspector;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfPosition;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.signature.GenericSignatureParser;
import java.util.Iterator;
+import java.util.ListIterator;
import java.util.function.Predicate;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.LineNumberNode;
public class FoundMethodSubject extends MethodSubject {
@@ -134,6 +144,69 @@
}
@Override
+ public boolean hasLineNumberTable() {
+ Code code = getMethod().getCode();
+ if (code.isDexCode()) {
+ DexCode dexCode = code.asDexCode();
+ if (dexCode.getDebugInfo() != null) {
+ for (DexDebugEvent event : dexCode.getDebugInfo().events) {
+ if (event instanceof DexDebugEvent.Default) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ if (code.isCfCode()) {
+ for (CfInstruction insn : code.asCfCode().getInstructions()) {
+ if (insn instanceof CfPosition) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (code.isJarCode()) {
+ ListIterator<AbstractInsnNode> it = code.asJarCode().getNode().instructions.iterator();
+ while (it.hasNext()) {
+ if (it.next() instanceof LineNumberNode) {
+ return true;
+ }
+ }
+ return false;
+ }
+ throw new Unreachable("Unexpected code type: " + code.getClass().getSimpleName());
+ }
+
+ @Override
+ public boolean hasLocalVariableTable() {
+ Code code = getMethod().getCode();
+ if (code.isDexCode()) {
+ DexCode dexCode = code.asDexCode();
+ if (dexCode.getDebugInfo() != null) {
+ for (DexString parameter : dexCode.getDebugInfo().parameters) {
+ if (parameter != null) {
+ return true;
+ }
+ }
+ for (DexDebugEvent event : dexCode.getDebugInfo().events) {
+ if (event instanceof DexDebugEvent.StartLocal) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ if (code.isCfCode()) {
+ return !code.asCfCode().getLocalVariables().isEmpty();
+ }
+ if (code.isJarCode()) {
+ return code.asJarCode().getNode().localVariables != null
+ && !code.asJarCode().getNode().localVariables.isEmpty();
+ }
+ throw new Unreachable("Unexpected code type: " + code.getClass().getSimpleName());
+ }
+
+ @Override
public String toString() {
return dexMethod.toSourceString();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 6eaaf5f..55030ca 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -32,4 +32,8 @@
Predicate<InstructionSubject> filter) {
return null;
}
+
+ public abstract boolean hasLineNumberTable();
+
+ public abstract boolean hasLocalVariableTable();
}
diff --git a/tools/build_r8lib.py b/tools/build_r8lib.py
index 4b7473e..5af6d4d 100755
--- a/tools/build_r8lib.py
+++ b/tools/build_r8lib.py
@@ -9,6 +9,7 @@
'''
import argparse
+import gradle
import os
import subprocess
import toolhelper
@@ -16,39 +17,70 @@
parser = argparse.ArgumentParser(description=__doc__.strip(),
formatter_class=argparse.RawTextHelpFormatter)
-
-SAMPLE_JAR = os.path.join(utils.REPO_ROOT, 'tests/d8_api_usage_sample.jar')
-R8LIB_JAR = os.path.join(utils.LIBS, 'r8lib.jar')
-R8LIB_MAP_FILE = os.path.join(utils.LIBS, 'r8lib-map.txt')
+parser.add_argument('-e', '--exclude_deps', action='store_true',
+ help='Create lib jar without dependencies')
+parser.add_argument('-k', '--keep', default=utils.R8LIB_KEEP_RULES,
+ help='Keep rules file for lib')
+parser.add_argument('-n', '--no_relocate', action='store_true',
+ help='Create lib jar without relocating libraries')
+parser.add_argument('-o', '--out', default=None,
+ help='Output for built library')
+parser.add_argument('-t', '--target', default='r8',
+ help='Compile target for library')
API_LEVEL = 26
-ANDROID_JAR = 'third_party/android_jar/lib-v%s/android.jar' % API_LEVEL
+DEPS_JAR = os.path.join(utils.LIBS, 'deps.jar')
+SAMPLE_JAR = os.path.join(utils.REPO_ROOT, 'tests', 'd8_api_usage_sample.jar')
-
-def build_r8lib(output_path=None, output_map=None, **kwargs):
+def build_r8lib(target, exclude_deps, no_relocate, keep_rules_path,
+ output_path, **kwargs):
+ # Clean the build directory to ensure no repackaging of any existing
+ # lib or deps.
+ gradle.RunGradle(['clean'])
+ lib_args = [target]
+ deps_args = ['repackageDeps']
+ if exclude_deps:
+ lib_args.append('-Pexclude_deps')
+ if no_relocate:
+ lib_args.append('-Plib_no_relocate')
+ deps_args.append('-Plib_no_relocate')
+ # Produce the r8lib target to be processed later.
+ gradle.RunGradle(lib_args)
+ target_lib = os.path.join(utils.LIBS, target + '.jar')
+ temp_lib = os.path.join(utils.LIBS, target + '_to_process.jar')
+ os.rename(target_lib, temp_lib)
+ # Produce the dependencies needed for running r8 on lib.jar.
+ gradle.RunGradle(deps_args)
+ temp_deps = os.path.join(utils.LIBS, target + 'lib_deps.jar')
+ os.rename(DEPS_JAR, temp_deps)
+ # Produce R8 for compiling lib
if output_path is None:
- output_path = R8LIB_JAR
- if output_map is None:
- output_map = R8LIB_MAP_FILE
+ output_path = target + 'lib.jar'
+ output_map_path = os.path.splitext(output_path)[0] + '.map'
toolhelper.run(
'r8',
('--release',
'--classfile',
'--lib', utils.RT_JAR,
- utils.R8_JAR,
+ '--lib', temp_deps,
+ temp_lib,
'--output', output_path,
- '--pg-conf', utils.R8LIB_KEEP_RULES,
- '--pg-map-output', output_map),
+ '--pg-conf', keep_rules_path,
+ '--pg-map-output', output_map_path),
**kwargs)
+ if exclude_deps:
+ return [output_path, temp_deps]
+ else:
+ return [output_path]
-def test_d8sample():
+def test_d8sample(paths):
with utils.TempDir() as path:
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.apiusagesample.D8ApiUsageSample',
'--output', path,
'--min-api', str(API_LEVEL),
- '--lib', ANDROID_JAR,
+ '--lib', utils.get_android_jar(API_LEVEL),
'--classpath', utils.R8_JAR,
'--main-dex-list', '/dev/null',
os.path.join(utils.BUILD, 'test/examples/hello.jar')]
@@ -56,30 +88,30 @@
subprocess.check_call(args)
-def test_r8command():
+def test_r8command(paths):
with utils.TempDir() as path:
- # SAMPLE_JAR and R8LIB_JAR should not have any classes in common, since e.g.
- # R8CommandParser should have been minified in R8LIB_JAR.
- # Just in case R8CommandParser is also present in R8LIB_JAR, we put
+ # SAMPLE_JAR and LIB_JAR should not have any classes in common, since e.g.
+ # R8CommandParser should have been minified in LIB_JAR.
+ # Just in case R8CommandParser is also present in LIB_JAR, we put
# SAMPLE_JAR first on the classpath to use its version of R8CommandParser.
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.r8.R8CommandParser',
'--output', path + "/output.zip",
'--min-api', str(API_LEVEL),
- '--lib', ANDROID_JAR,
+ '--lib', utils.get_android_jar(API_LEVEL),
'--main-dex-list', '/dev/null',
os.path.join(utils.BUILD, 'test/examples/hello.jar')]
utils.PrintCmd(args)
subprocess.check_call(args)
-def test_r8cfcommand():
+def test_r8cfcommand(paths):
with utils.TempDir() as path:
- # SAMPLE_JAR and R8LIB_JAR should not have any classes in common, since e.g.
- # R8CommandParser should have been minified in R8LIB_JAR.
- # Just in case R8CommandParser is also present in R8LIB_JAR, we put
+ # SAMPLE_JAR and LIB_JAR should not have any classes in common, since e.g.
+ # R8CommandParser should have been minified in LIB_JAR.
+ # Just in case R8CommandParser is also present in LIB_JAR, we put
# SAMPLE_JAR first on the classpath to use its version of R8CommandParser.
- args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, R8LIB_JAR),
+ args = ['java', '-cp', '%s:%s' % (SAMPLE_JAR, ":".join(paths)),
'com.android.tools.r8.R8CommandParser',
'--classfile',
'--output', path + "/output.jar",
@@ -91,12 +123,16 @@
def main():
# Handle --help
- parser.parse_args()
-
- build_r8lib()
- test_d8sample()
- test_r8command()
- test_r8cfcommand()
+ args = parser.parse_args()
+ output_paths = build_r8lib(
+ args.target, args.exclude_deps, args.no_relocate, args.keep, args.out)
+ if args.target == 'r8':
+ gradle.RunGradle(['buildExampleJars'])
+ test_r8command(output_paths)
+ test_r8cfcommand(output_paths)
+ if args.target == 'd8':
+ gradle.RunGradle(['buildExampleJars'])
+ test_d8sample(output_paths)
if __name__ == '__main__':