Merge commit '23d77afb55650c59e5cf224c33c0fbc1cfee76fb' into dev-release
diff --git a/build.gradle b/build.gradle
index 92e940a..8d1eb6b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -610,6 +610,7 @@
options.errorprone.enabled = true
options.errorprone.disableAllChecks = true
options.errorprone.check('ClassCanBeStatic', CheckSeverity.ERROR)
+ options.errorprone.check('CollectionIncompatibleType', CheckSeverity.ERROR)
options.errorprone.check('OperatorPrecedence', CheckSeverity.ERROR)
options.errorprone.check('RemoveUnusedImports', CheckSeverity.ERROR)
options.errorprone.check('MissingOverride', CheckSeverity.ERROR)
@@ -695,25 +696,25 @@
}
}
-task repackageDeps(type: ShadowJar) {
+task repackageDepsNew(type: ShadowJar) {
configurations = [project.configurations.runtimeClasspath]
mergeServiceFiles(it)
exclude { it.getRelativePath().getPathString() == "module-info.class" }
exclude { it.getRelativePath().getPathString().startsWith("META-INF/maven/") }
- baseName 'deps'
+ baseName 'deps_all'
}
-task repackageSources(type: ShadowJar) {
+task repackageSourcesNew(type: ShadowJar) {
from sourceSets.main.output
mergeServiceFiles(it)
- baseName 'sources'
+ baseName 'sources_main'
}
-task repackageSources11(type: ShadowJar) {
+task repackageSources11New(type: ShadowJar) {
dependsOn compileMainWithJava11
from file(java11ClassFiles)
mergeServiceFiles(it)
- baseName 'sources11'
+ baseName 'sources_main_11'
}
def r8CreateTask(name, baseNameName, sources, includeSwissArmyKnife) {
@@ -771,24 +772,26 @@
}
task r8WithDeps {
- dependsOn repackageSources
- dependsOn repackageDeps
+ dependsOn repackageSourcesNew
+ dependsOn repackageDepsNew
+ inputs.files ([repackageSourcesNew.outputs, repackageDepsNew.outputs])
def r8Task = r8CreateTask(
'WithDeps',
'r8_with_deps',
- repackageSources.outputs.files + repackageDeps.outputs.files,
+ repackageSourcesNew.outputs.files + repackageDepsNew.outputs.files,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
}
task r8WithDeps11 {
- dependsOn repackageSources11
- dependsOn repackageDeps
+ dependsOn repackageSources11New
+ dependsOn repackageDepsNew
+ inputs.files ([repackageSources11New.outputs, repackageDepsNew.outputs])
def r8Task = r8CreateTask(
'WithDeps11',
'r8_with_deps_11',
- repackageSources11.outputs.files + repackageDeps.outputs.files,
+ repackageSources11New.outputs.files + repackageDepsNew.outputs.files,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -797,21 +800,24 @@
task r8WithRelocatedDeps {
def output = "${buildDir}/libs/r8_with_relocated_deps.jar"
dependsOn r8RelocateTask(r8WithDeps, output)
+ inputs.files r8WithDeps.outputs.files
outputs.file output
}
task r8WithRelocatedDeps11 {
def output = "${buildDir}/libs/r8_with_relocated_deps_11.jar"
dependsOn r8RelocateTask(r8WithDeps11, output)
+ inputs.files r8WithDeps11.outputs.files
outputs.file output
}
task r8WithoutDeps {
- dependsOn repackageSources
+ dependsOn repackageSourcesNew
+ inputs.files repackageSourcesNew.outputs
def r8Task = r8CreateTask(
'WithoutDeps',
'r8_without_deps',
- repackageSources.outputs.files,
+ repackageSourcesNew.outputs.files,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -828,22 +834,24 @@
}
task r8NoManifestWithoutDeps {
- dependsOn repackageSources
+ dependsOn repackageSourcesNew
+ inputs.files repackageSourcesNew.outputs
def r8Task = r8CreateTask(
'NoManifestWithoutDeps',
'r8_no_manifest_without_deps',
- repackageSources.outputs.files,
+ repackageSourcesNew.outputs.files,
false)
dependsOn r8Task
outputs.files r8Task.outputs.files
}
task r8NoManifestWithDeps {
- dependsOn repackageSources
+ dependsOn repackageSourcesNew
+ inputs.files ([repackageSourcesNew.outputs, repackageDepsNew.outputs])
def r8Task = r8CreateTask(
'NoManifestWithDeps',
'r8_no_manifest_with_deps',
- repackageSources.outputs.files + repackageDeps.outputs.files,
+ repackageSourcesNew.outputs.files + repackageDepsNew.outputs.files,
false)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -852,6 +860,7 @@
task r8NoManifestWithRelocatedDeps {
def output = "${buildDir}/libs/r8_no_manifest_with_relocated_deps.jar"
dependsOn r8RelocateTask(r8NoManifestWithDeps, output)
+ inputs.files r8NoManifestWithDeps.outputs.files
outputs.file output
}
@@ -925,7 +934,7 @@
def output = "$buildDir/libs/r8tests.jar"
outputs.file output
workingDir = projectDir
- inputs.files ([testJarSources.outputs, r8WithDeps.outputs])
+ inputs.files (testJarSources.outputs.files + r8WithDeps.outputs.files)
commandLine baseR8CommandLine([
"relocator",
"--input",
@@ -942,20 +951,21 @@
// TODO(b/154785341): We should remove this.
standardOutput new FileOutputStream(r8LibGeneratedKeepRulesPath)
}
- dependsOn r8WithRelocatedDeps
- dependsOn r8NoManifestWithDeps
+ // Depend on r8WithDeps for running baseR8CommandLine.
+ dependsOn r8WithDeps
+ dependsOn r8NoManifestWithRelocatedDeps
dependsOn testJar
dependsOn downloadOpenJDKrt
inputs.files ([
- r8WithRelocatedDeps.outputs,
- r8NoManifestWithDeps.outputs,
+ r8WithDeps.outputs,
+ r8NoManifestWithRelocatedDeps.outputs,
testJar.outputs])
outputs.file r8LibGeneratedKeepRulesPath
commandLine baseR8CommandLine([
"printuses",
"--keeprules-allowobfuscation",
"third_party/openjdk/openjdk-rt-1.8/rt.jar",
- r8NoManifestWithDeps.outputs.files[0],
+ r8NoManifestWithRelocatedDeps.outputs.files[0],
testJar.outputs.files[0]])
workingDir = projectDir
}
@@ -974,6 +984,7 @@
r8NoManifestWithRelocatedDeps,
r8LibPath,
).dependsOn(generateR8LibKeepRules)
+ inputs.files r8NoManifestWithRelocatedDeps.outputs.files
outputs.file r8LibPath
}
@@ -984,8 +995,9 @@
r8NoManifestWithoutDeps,
r8LibExludeDepsPath,
"--release",
- repackageDeps.outputs.files
- ).dependsOn(repackageDeps)
+ repackageDepsNew.outputs.files
+ ).dependsOn(repackageDepsNew)
+ inputs.files ([r8NoManifestWithoutDeps.outputs, repackageDepsNew.outputs])
outputs.file r8LibExludeDepsPath
}
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index e8c6bb1..3cd04b1 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -14,10 +14,10 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.conversion.IRConverter;
@@ -183,7 +183,7 @@
ThreadUtils.processItems(
appInfo.classes(),
clazz -> {
- DexEncodedMethod classInitializer = clazz.getClassInitializer();
+ ProgramMethod classInitializer = clazz.getProgramClassInitializer();
if (classInitializer != null) {
analysis.processNewlyLiveMethod(classInitializer);
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 164c572..5c815bc 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -375,7 +375,7 @@
internal.debug = getMode() == CompilationMode.DEBUG;
internal.programConsumer = getProgramConsumer();
if (internal.programConsumer instanceof ClassFileConsumer) {
- internal.enableCfInterfaceMethodDesugaring = true;
+ internal.cfToCfDesugar = true;
}
internal.mainDexListConsumer = getMainDexListConsumer();
internal.minimalMainDex = internal.debug || minimalMainDex;
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index cf9684c..dea3bb8 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -87,11 +87,15 @@
ExecutorService executorService)
throws CompilationFailedException {
try {
+ assert !options.cfToCfDesugar;
ExceptionUtils.withD8CompilationHandler(
options.reporter,
() -> {
+ options.cfToCfDesugar = true;
desugar(app, options, executorService);
+ options.cfToCfDesugar = false;
});
+ assert !options.cfToCfDesugar;
if (shrink) {
R8.run(r8Command);
} else {
@@ -105,6 +109,7 @@
private static void desugar(
AndroidApp inputApp, InternalOptions options, ExecutorService executor) throws IOException {
Timing timing = Timing.create("L8 desugaring", options);
+ assert options.cfToCfDesugar;
try {
// Disable global optimizations.
options.disableGlobalOptimizations();
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 0b4f28b..9a26221 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexAnnotation;
@@ -19,6 +21,7 @@
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
@@ -244,18 +247,18 @@
registerTypeReference(field.field.type);
}
- private void registerMethod(DexEncodedMethod method) {
+ private void registerMethod(ProgramMethod method) {
DexEncodedMethod superTarget =
appInfo
- .resolveMethod(method.holder(), method.method)
+ .resolveMethod(method.getHolder(), method.getReference())
.lookupInvokeSpecialTarget(context, appInfo);
if (superTarget != null) {
addMethod(superTarget.method);
}
- for (DexType type : method.method.proto.parameters.values) {
+ for (DexType type : method.getDefinition().parameters().values) {
registerTypeReference(type);
}
- for (DexAnnotation annotation : method.annotations().annotations) {
+ for (DexAnnotation annotation : method.getDefinition().annotations().annotations) {
if (annotation.annotation.type == appInfo.dexItemFactory().annotationThrows) {
DexValueArray dexValues = annotation.annotation.elements[0].value.asDexValueArray();
for (DexValue dexValType : dexValues.getValues()) {
@@ -263,7 +266,7 @@
}
}
}
- registerTypeReference(method.method.proto.returnType);
+ registerTypeReference(method.getDefinition().returnType());
method.registerCodeReferences(this);
}
@@ -289,13 +292,11 @@
List<DexType> directInterfaces = LambdaDescriptor.getInterfaces(callSite, appInfo);
if (directInterfaces != null) {
for (DexType directInterface : directInterfaces) {
- DexClass clazz = appInfo.definitionFor(directInterface);
+ DexProgramClass clazz = asProgramClassOrNull(appInfo.definitionFor(directInterface));
if (clazz != null) {
- for (DexEncodedMethod encodedMethod : clazz.virtualMethods()) {
- if (encodedMethod.method.name.equals(callSite.methodName)) {
- registerMethod(encodedMethod);
- }
- }
+ clazz.forEachProgramVirtualMethodMatching(
+ definition -> definition.getReference().name.equals(callSite.methodName),
+ this::registerMethod);
}
}
}
@@ -360,14 +361,14 @@
private void analyze() {
UseCollector useCollector = new UseCollector(appInfo.dexItemFactory());
- for (DexProgramClass dexProgramClass : application.classes()) {
- useCollector.setContext(dexProgramClass);
- useCollector.registerSuperType(dexProgramClass, dexProgramClass.superType);
- for (DexType implementsType : dexProgramClass.interfaces.values) {
- useCollector.registerSuperType(dexProgramClass, implementsType);
+ for (DexProgramClass clazz : application.classes()) {
+ useCollector.setContext(clazz);
+ useCollector.registerSuperType(clazz, clazz.superType);
+ for (DexType implementsType : clazz.interfaces.values) {
+ useCollector.registerSuperType(clazz, implementsType);
}
- dexProgramClass.forEachMethod(useCollector::registerMethod);
- dexProgramClass.forEachField(useCollector::registerField);
+ clazz.forEachProgramMethod(useCollector::registerMethod);
+ clazz.forEachField(useCollector::registerField);
}
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 30201ce..51b0aaf 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -32,7 +32,6 @@
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.analysis.proto.GeneratedExtensionRegistryShrinker;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
@@ -52,7 +51,6 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.kotlin.KotlinInfoCollector;
-import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.Minifier;
import com.android.tools.r8.naming.NamingLens;
@@ -682,11 +680,6 @@
shrinker.removeDeadBuilderReferencesFromDynamicMethods(
appViewWithLiveness, executorService, timing));
- if (Log.ENABLED && Log.isLoggingEnabledFor(GeneratedExtensionRegistryShrinker.class)) {
- appView.withGeneratedExtensionRegistryShrinker(
- GeneratedExtensionRegistryShrinker::logRemainingProtoExtensionFields);
- }
-
if (options.isShrinking()) {
// Mark dead proto extensions fields as neither being read nor written. This step must
// run prior to the tree pruner.
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 59b3c8b..a2a814a 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -112,28 +112,30 @@
}
@Override
- void writeMethod(DexEncodedMethod method, PrintStream ps) {
+ void writeMethod(ProgramMethod method, PrintStream ps) {
+ DexEncodedMethod definition = method.getDefinition();
ClassNameMapper naming = application.getProguardMap();
- String methodName = naming != null
- ? naming.originalSignatureOf(method.method).name
- : method.method.name.toString();
+ String methodName =
+ naming != null
+ ? naming.originalSignatureOf(method.getReference()).name
+ : method.getReference().name.toString();
ps.println("#");
ps.println("# Method: '" + methodName + "':");
- writeAnnotations(null, method.annotations(), ps);
- ps.println("# " + method.accessFlags);
+ writeAnnotations(null, definition.annotations(), ps);
+ ps.println("# " + definition.accessFlags);
ps.println("#");
ps.println();
- Code code = method.getCode();
+ Code code = definition.getCode();
if (code != null) {
if (writeIR) {
writeIR(method, ps);
} else {
- ps.println(code.toString(method, naming));
+ ps.println(code.toString(definition, naming));
}
}
}
- private void writeIR(DexEncodedMethod method, PrintStream ps) {
+ private void writeIR(ProgramMethod method, PrintStream ps) {
CfgPrinter printer = new CfgPrinter();
new IRConverter(appInfo, options, timing, printer)
.processMethod(
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 93ca81d..b68b839 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -5,6 +5,8 @@
import static com.android.tools.r8.graph.DexCode.FAKE_THIS_PREFIX;
import static com.android.tools.r8.graph.DexCode.FAKE_THIS_SUFFIX;
+import static org.objectweb.asm.Opcodes.V1_5;
+import static org.objectweb.asm.Opcodes.V1_6;
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.CfFrame;
@@ -211,8 +213,8 @@
}
for (CfInstruction instruction : instructions) {
if (instruction instanceof CfFrame
- && (classFileVersion <= 49
- || (classFileVersion == 50 && !options.shouldKeepStackMapTable()))) {
+ && (classFileVersion <= V1_5
+ || (classFileVersion == V1_6 && !options.shouldKeepStackMapTable()))) {
continue;
}
instruction.write(visitor, initClassLens, namingLens);
@@ -287,15 +289,14 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- return internalBuildPossiblyWithLocals(
- encodedMethod, encodedMethod, appView, null, null, origin, null);
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ return internalBuildPossiblyWithLocals(method, method, appView, null, null, origin, null);
}
@Override
public IRCode buildInliningIR(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
@@ -304,29 +305,23 @@
assert valueNumberGenerator != null;
assert callerPosition != null;
return internalBuildPossiblyWithLocals(
- context,
- encodedMethod,
- appView,
- valueNumberGenerator,
- callerPosition,
- origin,
- methodProcessor);
+ context, method, appView, valueNumberGenerator, callerPosition, origin, methodProcessor);
}
// First build entry. Will either strip locals or build with locals.
private IRCode internalBuildPossiblyWithLocals(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator generator,
Position callerPosition,
Origin origin,
MethodProcessor methodProcessor) {
- if (!encodedMethod.keepLocals(appView.options())) {
+ if (!method.getDefinition().keepLocals(appView.options())) {
return internalBuild(
Collections.emptyList(),
context,
- encodedMethod,
+ method,
appView,
generator,
callerPosition,
@@ -334,14 +329,14 @@
methodProcessor);
} else {
return internalBuildWithLocals(
- context, encodedMethod, appView, generator, callerPosition, origin, methodProcessor);
+ context, method, appView, generator, callerPosition, origin, methodProcessor);
}
}
// When building with locals, on invalid debug info, retry build without locals info.
private IRCode internalBuildWithLocals(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator generator,
Position callerPosition,
@@ -351,18 +346,18 @@
return internalBuild(
Collections.unmodifiableList(localVariables),
context,
- encodedMethod,
+ method,
appView,
generator,
callerPosition,
origin,
methodProcessor);
} catch (InvalidDebugInfoException e) {
- appView.options().warningInvalidDebugInfo(encodedMethod, origin, e);
+ appView.options().warningInvalidDebugInfo(method, origin, e);
return internalBuild(
Collections.emptyList(),
context,
- encodedMethod,
+ method,
appView,
generator,
callerPosition,
@@ -374,8 +369,8 @@
// Inner-most subroutine for building. Must only be called by the two internalBuildXYZ above.
private IRCode internalBuild(
List<LocalVariableInfo> localVariables,
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator generator,
Position callerPosition,
@@ -385,22 +380,32 @@
new CfSourceCode(
this,
localVariables,
- encodedMethod,
- appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
+ method,
+ appView.graphLense().getOriginalMethodSignature(method.getReference()),
callerPosition,
origin,
appView);
- IRBuilder builder = methodProcessor == null ?
- IRBuilder.create(encodedMethod, appView, source, origin) :
- IRBuilder
- .createForInlining(encodedMethod, appView, source, origin, methodProcessor, generator);
+ IRBuilder builder =
+ methodProcessor == null
+ ? IRBuilder.create(method, appView, source, origin)
+ : IRBuilder.createForInlining(
+ method, appView, source, origin, methodProcessor, generator);
return builder.build(context);
}
@Override
- public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
for (CfInstruction instruction : instructions) {
- instruction.registerUse(registry, method.holder());
+ instruction.registerUse(registry, method.getHolderType());
}
for (CfTryCatch tryCatch : tryCatchRanges) {
for (DexType guard : tryCatch.guards) {
@@ -505,7 +510,7 @@
}
public ConstraintWithTarget computeInliningConstraint(
- DexEncodedMethod encodedMethod,
+ ProgramMethod method,
AppView<AppInfoWithLiveness> appView,
GraphLense graphLense,
DexType invocationContext) {
@@ -521,7 +526,7 @@
// Model a synchronized method as having a monitor instruction.
ConstraintWithTarget constraint =
- encodedMethod.accessFlags.isSynchronized()
+ method.getDefinition().isSynchronized()
? inliningConstraints.forMonitor()
: ConstraintWithTarget.ALWAYS;
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathMethod.java b/src/main/java/com/android/tools/r8/graph/ClasspathMethod.java
new file mode 100644
index 0000000..9d2a941
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathMethod.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.logging.Log;
+
+/** Type representing a method definition on the classpath and its holder. */
+public final class ClasspathMethod extends DexClassAndMethod {
+
+ public ClasspathMethod(DexClasspathClass holder, DexEncodedMethod method) {
+ super(holder, method);
+ }
+
+ public void registerCodeReferencesForDesugaring(UseRegistry registry) {
+ Code code = getDefinition().getCode();
+ if (code != null) {
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Registering definitions reachable from `%s`.", this);
+ }
+ code.registerCodeReferencesForDesugaring(this, registry);
+ }
+ }
+
+ @Override
+ public boolean isClasspathMethod() {
+ return true;
+ }
+
+ @Override
+ public ClasspathMethod asClasspathMethod() {
+ return this;
+ }
+
+ @Override
+ public DexClasspathClass getHolder() {
+ DexClass holder = super.getHolder();
+ assert holder.isClasspathClass();
+ return holder.asClasspathClass();
+ }
+}
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 8e81c8e..9f384ca 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -17,11 +17,11 @@
public abstract class Code extends CachedHashValueDexItem {
- public abstract IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin);
+ public abstract IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin);
public IRCode buildInliningIR(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
@@ -31,7 +31,10 @@
+ getClass().getCanonicalName());
}
- public abstract void registerCodeReferences(DexEncodedMethod method, UseRegistry registry);
+ public abstract void registerCodeReferences(ProgramMethod method, UseRegistry registry);
+
+ public abstract void registerCodeReferencesForDesugaring(
+ ClasspathMethod method, UseRegistry registry);
public void registerArgumentReferences(DexEncodedMethod method, ArgumentUse registry) {
throw new Unreachable();
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index a81e59c..c83010d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -88,7 +88,7 @@
clazz.forEachField(field -> writeField(field, ps));
writeFieldsFooter(clazz, ps);
writeMethodsHeader(clazz, ps);
- clazz.forEachMethod(method -> writeMethod(method, ps));
+ clazz.forEachProgramMethod(method -> writeMethod(method, ps));
writeMethodsFooter(clazz, ps);
writeClassFooter(clazz, ps);
}
@@ -111,7 +111,7 @@
// Do nothing.
}
- abstract void writeMethod(DexEncodedMethod method, PrintStream ps);
+ abstract void writeMethod(ProgramMethod method, PrintStream ps);
void writeMethodsFooter(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
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 444459f..5bcb25c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -511,6 +511,10 @@
return null;
}
+ public boolean isPrivate() {
+ return accessFlags.isPrivate();
+ }
+
public boolean isPublic() {
return accessFlags.isPublic();
}
@@ -822,7 +826,7 @@
public boolean hasStaticSynchronizedMethods() {
for (DexEncodedMethod encodedMethod : directMethods()) {
- if (encodedMethod.accessFlags.isStatic() && encodedMethod.accessFlags.isSynchronized()) {
+ if (encodedMethod.isStatic() && encodedMethod.isSynchronized()) {
return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index f77d55b..c6c2f07 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.origin.Origin;
public class DexClassAndMethod implements LookupTarget {
@@ -12,7 +13,10 @@
private final DexEncodedMethod method;
DexClassAndMethod(DexClass holder, DexEncodedMethod method) {
+ assert holder != null;
+ assert method != null;
assert holder.type == method.holder();
+ assert holder.isProgramClass() == (this instanceof ProgramMethod);
this.holder = holder;
this.method = method;
}
@@ -20,13 +24,16 @@
public static DexClassAndMethod create(DexClass holder, DexEncodedMethod method) {
if (holder.isProgramClass()) {
return new ProgramMethod(holder.asProgramClass(), method);
- } else {
+ } else if (holder.isLibraryClass()) {
return new DexClassAndMethod(holder, method);
+ } else {
+ assert holder.isClasspathClass();
+ return new ClasspathMethod(holder.asClasspathClass(), method);
}
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(Object object) {
throw new Unreachable("Unsupported attempt at comparing Class and DexClassAndMethod");
}
@@ -49,10 +56,30 @@
return holder;
}
+ public DexType getHolderType() {
+ return holder.type;
+ }
+
public DexEncodedMethod getDefinition() {
return method;
}
+ public DexMethod getReference() {
+ return method.method;
+ }
+
+ public Origin getOrigin() {
+ return holder.origin;
+ }
+
+ public boolean isClasspathMethod() {
+ return false;
+ }
+
+ public ClasspathMethod asClasspathMethod() {
+ return null;
+ }
+
public boolean isProgramMethod() {
return false;
}
@@ -60,4 +87,13 @@
public ProgramMethod asProgramMethod() {
return null;
}
+
+ public String toSourceString() {
+ return method.method.toSourceString();
+ }
+
+ @Override
+ public String toString() {
+ return toSourceString();
+ }
}
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 e9e47b6..b4eeb9e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -214,20 +214,20 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
DexSourceCode source =
new DexSourceCode(
this,
- encodedMethod,
- appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
+ method,
+ appView.graphLense().getOriginalMethodSignature(method.getReference()),
null);
- return IRBuilder.create(encodedMethod,appView,source,origin).build(encodedMethod);
+ return IRBuilder.create(method, appView, source, origin).build(method);
}
@Override
public IRCode buildInliningIR(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
@@ -236,15 +236,25 @@
DexSourceCode source =
new DexSourceCode(
this,
- encodedMethod,
- appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
+ method,
+ appView.graphLense().getOriginalMethodSignature(method.getReference()),
callerPosition);
return IRBuilder.createForInlining(
- encodedMethod, appView, source, origin, methodProcessor, valueNumberGenerator).build(context);
+ method, appView, source, origin, methodProcessor, valueNumberGenerator)
+ .build(context);
}
@Override
- public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
for (Instruction insn : instructions) {
insn.registerUse(registry);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 43536b9..c589524 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -207,7 +207,7 @@
&& singleValue.asSingleFieldValue().getField() == field) {
return null;
}
- if (singleValue.isMaterializableInContext(appView, code.method().holder())) {
+ if (singleValue.isMaterializableInContext(appView, code.context())) {
TypeElement type = TypeElement.fromDexType(field.type, maybeNull(), appView);
return singleValue.createMaterializingInstruction(
appView, code, TypeAndLocalInfoSupplier.create(type, local));
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 816a515..b81c877 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -9,6 +9,7 @@
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE;
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_INLINING_CANDIDATE_SUBCLASS;
import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
import com.android.tools.r8.cf.code.CfConstNull;
@@ -37,11 +38,8 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring.DexFieldWithAccess;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -57,12 +55,10 @@
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
-import com.android.tools.r8.logging.Log;
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;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AnnotationRemover;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
@@ -257,10 +253,18 @@
assert parameterAnnotationsList != null;
}
+ public DexMethod getReference() {
+ return method;
+ }
+
public DexTypeList parameters() {
return method.proto.parameters;
}
+ public DexProto proto() {
+ return method.proto;
+ }
+
public DexType returnType() {
return method.proto.returnType;
}
@@ -298,6 +302,20 @@
return false;
}
+ public ProgramMethod asProgramMethod(DexDefinitionSupplier definitions) {
+ assert method.holder.isClassType();
+ DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(method));
+ if (clazz != null) {
+ return new ProgramMethod(clazz, this);
+ }
+ return null;
+ }
+
+ public static ProgramMethod asProgramMethodOrNull(
+ DexEncodedMethod method, DexDefinitionSupplier definitions) {
+ return method != null ? method.asProgramMethod(definitions) : null;
+ }
+
public boolean isProcessed() {
checkIfObsolete();
return compilationState != CompilationState.NOT_PROCESSED;
@@ -315,10 +333,22 @@
return accessFlags.isFinal();
}
+ public boolean isNative() {
+ return accessFlags.isNative();
+ }
+
+ public boolean isPrivate() {
+ return accessFlags.isPrivate();
+ }
+
public boolean isPublic() {
return accessFlags.isPublic();
}
+ public boolean isSynchronized() {
+ return accessFlags.isSynchronized();
+ }
+
public boolean isInitializer() {
checkIfObsolete();
return isInstanceInitializer() || isClassInitializer();
@@ -448,13 +478,13 @@
}
public boolean isInliningCandidate(
- DexEncodedMethod container,
+ ProgramMethod container,
Reason inliningReason,
AppInfoWithClassHierarchy appInfo,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
checkIfObsolete();
return isInliningCandidate(
- container.holder(), inliningReason, appInfo, whyAreYouNotInliningReporter);
+ container.getHolderType(), inliningReason, appInfo, whyAreYouNotInliningReporter);
}
public boolean isInliningCandidate(
@@ -552,23 +582,6 @@
compilationState = CompilationState.NOT_PROCESSED;
}
- public IRCode buildIR(AppView<?> appView, Origin origin) {
- checkIfObsolete();
- return code == null ? null : code.buildIR(this, appView, origin);
- }
-
- public IRCode buildInliningIR(
- DexEncodedMethod context,
- AppView<?> appView,
- ValueNumberGenerator valueNumberGenerator,
- Position callerPosition,
- Origin origin,
- MethodProcessor methodProcessor) {
- checkIfObsolete();
- return code.buildInliningIR(
- context, this, appView, valueNumberGenerator, callerPosition, origin, methodProcessor);
- }
-
public void setCode(Code newCode, AppView<?> appView) {
checkIfObsolete();
// If the locals are not kept, we might still need information to satisfy -keepparameternames.
@@ -936,7 +949,7 @@
return builder.build();
}
- public DexEncodedMethod toInitializerForwardingBridge(DexClass holder, DexMethod newMethod) {
+ public ProgramMethod toInitializerForwardingBridge(DexProgramClass holder, DexMethod newMethod) {
assert accessFlags.isPrivate()
: "Expected to create bridge for private constructor as part of nest-based access"
+ " desugaring";
@@ -958,11 +971,11 @@
builder.accessFlags.unsetPrivate();
builder.accessFlags.setSynthetic();
builder.accessFlags.setConstructor();
- return builder.build();
+ return new ProgramMethod(holder, builder.build());
}
- public static DexEncodedMethod createFieldAccessorBridge(
- DexFieldWithAccess fieldWithAccess, DexClass holder, DexMethod newMethod) {
+ public static ProgramMethod createFieldAccessorBridge(
+ DexFieldWithAccess fieldWithAccess, DexProgramClass holder, DexMethod newMethod) {
assert holder.type == fieldWithAccess.getHolder();
MethodAccessFlags accessFlags =
MethodAccessFlags.fromSharedAccessFlags(
@@ -987,13 +1000,15 @@
registry.registerStaticFieldWrite(fieldWithAccess.getField());
}
});
- return new DexEncodedMethod(
- newMethod,
- accessFlags,
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true);
+ return new ProgramMethod(
+ holder,
+ new DexEncodedMethod(
+ newMethod,
+ accessFlags,
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ code,
+ true));
}
public DexEncodedMethod toRenamedHolderMethod(DexType newHolderType, DexItemFactory factory) {
@@ -1025,7 +1040,7 @@
true);
}
- public DexEncodedMethod toStaticForwardingBridge(DexClass holder, DexMethod newMethod) {
+ public ProgramMethod toStaticForwardingBridge(DexProgramClass holder, DexMethod newMethod) {
assert accessFlags.isPrivate()
: "Expected to create bridge for private method as part of nest-based access desugaring";
Builder builder = syntheticBuilder(this);
@@ -1053,7 +1068,7 @@
if (holder.isInterface()) {
builder.accessFlags.setPublic();
}
- return builder.build();
+ return new ProgramMethod(holder, builder.build());
}
public DexEncodedMethod toForwardingMethod(DexClass holder, DexDefinitionSupplier definitions) {
@@ -1198,16 +1213,6 @@
return !annotations().isEmpty() || !parameterAnnotationsList.isEmpty();
}
- public void registerCodeReferences(UseRegistry registry) {
- checkIfObsolete();
- if (code != null) {
- if (Log.ENABLED) {
- Log.verbose(getClass(), "Registering definitions reachable from `%s`.", method);
- }
- code.registerCodeReferences(this, registry);
- }
- }
-
public static int slowCompare(DexEncodedMethod m1, DexEncodedMethod m2) {
return m1.method.slowCompareTo(m2.method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index bda291b..e27c7b4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
+import static com.google.common.base.Predicates.alwaysTrue;
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
@@ -14,6 +15,7 @@
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.TraversalContinuation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -21,6 +23,9 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.function.Supplier;
public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {
@@ -128,6 +133,79 @@
synthesizedDirectlyFrom.forEach(this::addSynthesizedFrom);
}
+ public void forEachProgramMethod(Consumer<ProgramMethod> consumer) {
+ forEachProgramMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachProgramMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<ProgramMethod> consumer) {
+ methodCollection.forEachMethodMatching(
+ predicate, method -> consumer.accept(new ProgramMethod(this, method)));
+ }
+
+ public void forEachProgramDirectMethod(Consumer<ProgramMethod> consumer) {
+ forEachProgramDirectMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachProgramDirectMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<ProgramMethod> consumer) {
+ methodCollection.forEachDirectMethodMatching(
+ predicate, method -> consumer.accept(new ProgramMethod(this, method)));
+ }
+
+ public void forEachProgramVirtualMethod(Consumer<ProgramMethod> consumer) {
+ forEachProgramVirtualMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachProgramVirtualMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<ProgramMethod> consumer) {
+ methodCollection.forEachVirtualMethodMatching(
+ predicate, method -> consumer.accept(new ProgramMethod(this, method)));
+ }
+
+ public ProgramMethod getProgramClassInitializer() {
+ return toProgramMethodOrNull(getClassInitializer());
+ }
+
+ public ProgramMethod getProgramDefaultInitializer() {
+ return getProgramInitializer(DexType.EMPTY_ARRAY);
+ }
+
+ public ProgramMethod getProgramInitializer(DexType[] types) {
+ return toProgramMethodOrNull(getInitializer(types));
+ }
+
+ public ProgramMethod lookupProgramMethod(DexMethod reference) {
+ return toProgramMethodOrNull(getMethodCollection().getMethod(reference));
+ }
+
+ private ProgramMethod toProgramMethodOrNull(DexEncodedMethod method) {
+ if (method != null) {
+ return new ProgramMethod(this, method);
+ }
+ return null;
+ }
+
+ public TraversalContinuation traverseProgramMethods(
+ Function<ProgramMethod, TraversalContinuation> fn) {
+ return getMethodCollection().traverse(method -> fn.apply(new ProgramMethod(this, method)));
+ }
+
+ public TraversalContinuation traverseProgramInstanceInitializers(
+ Function<ProgramMethod, TraversalContinuation> fn) {
+ return traverseProgramMethods(fn, DexEncodedMethod::isInstanceInitializer);
+ }
+
+ public TraversalContinuation traverseProgramMethods(
+ Function<ProgramMethod, TraversalContinuation> fn, Predicate<DexEncodedMethod> predicate) {
+ return getMethodCollection()
+ .traverse(
+ method ->
+ predicate.test(method)
+ ? fn.apply(new ProgramMethod(this, method))
+ : TraversalContinuation.CONTINUE);
+ }
+
public boolean originatesFromDexResource() {
return originKind == Kind.DEX;
}
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 597e6e0..d17a4d2 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -209,14 +209,14 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- return asCfCode().buildIR(encodedMethod, appView, origin);
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ return asCfCode().buildIR(method, appView, origin);
}
@Override
public IRCode buildInliningIR(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
@@ -225,7 +225,7 @@
return asCfCode()
.buildInliningIR(
context,
- encodedMethod,
+ method,
appView,
valueNumberGenerator,
callerPosition,
@@ -234,11 +234,16 @@
}
@Override
- public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
asCfCode().registerCodeReferences(method, registry);
}
@Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ asCfCode().registerCodeReferencesForDesugaring(method, registry);
+ }
+
+ @Override
public void registerArgumentReferences(DexEncodedMethod method, ArgumentUse registry) {
asCfCode().registerArgumentReferences(method, registry);
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index 5b05c3f..5a5db62 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -38,6 +38,16 @@
}
@Override
+ public int numberOfDirectMethods() {
+ return directMethods.length;
+ }
+
+ @Override
+ public int numberOfVirtualMethods() {
+ return virtualMethods.length;
+ }
+
+ @Override
int size() {
return directMethods.length + virtualMethods.length;
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index ec3e102..ac2685a 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -1,5 +1,7 @@
package com.android.tools.r8.graph;
+import static com.google.common.base.Predicates.alwaysTrue;
+
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.TraversalContinuation;
@@ -48,6 +50,14 @@
// Nothing to do.
}
+ public int numberOfDirectMethods() {
+ return backing.numberOfDirectMethods();
+ }
+
+ public int numberOfVirtualMethods() {
+ return backing.numberOfVirtualMethods();
+ }
+
public int size() {
return backing.size();
}
@@ -57,7 +67,45 @@
}
public void forEachMethod(Consumer<DexEncodedMethod> consumer) {
- backing.forEachMethod(consumer);
+ forEachMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<DexEncodedMethod> consumer) {
+ backing.forEachMethod(
+ method -> {
+ if (predicate.test(method)) {
+ consumer.accept(method);
+ }
+ });
+ }
+
+ public void forEachDirectMethod(Consumer<DexEncodedMethod> consumer) {
+ forEachDirectMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachDirectMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<DexEncodedMethod> consumer) {
+ backing.forEachDirectMethod(
+ method -> {
+ if (predicate.test(method)) {
+ consumer.accept(method);
+ }
+ });
+ }
+
+ public void forEachVirtualMethod(Consumer<DexEncodedMethod> consumer) {
+ forEachVirtualMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachVirtualMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<DexEncodedMethod> consumer) {
+ backing.forEachVirtualMethod(
+ method -> {
+ if (predicate.test(method)) {
+ consumer.accept(method);
+ }
+ });
}
public Iterable<DexEncodedMethod> methods() {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
index 913a563..56ab228 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.google.common.base.Predicates.alwaysTrue;
+
import com.android.tools.r8.utils.TraversalContinuation;
import java.util.Collection;
import java.util.List;
@@ -29,6 +31,10 @@
// Collection methods.
+ abstract int numberOfDirectMethods();
+
+ abstract int numberOfVirtualMethods();
+
abstract int size();
// Traversal methods.
@@ -36,13 +42,27 @@
abstract TraversalContinuation traverse(Function<DexEncodedMethod, TraversalContinuation> fn);
void forEachMethod(Consumer<DexEncodedMethod> fn) {
+ forEachMethod(fn, alwaysTrue());
+ }
+
+ void forEachMethod(Consumer<DexEncodedMethod> fn, Predicate<DexEncodedMethod> predicate) {
traverse(
method -> {
- fn.accept(method);
+ if (predicate.test(method)) {
+ fn.accept(method);
+ }
return TraversalContinuation.CONTINUE;
});
}
+ void forEachDirectMethod(Consumer<DexEncodedMethod> fn) {
+ forEachMethod(fn, this::belongsToDirectPool);
+ }
+
+ void forEachVirtualMethod(Consumer<DexEncodedMethod> fn) {
+ forEachMethod(fn, this::belongsToVirtualPool);
+ }
+
abstract Iterable<DexEncodedMethod> methods();
abstract List<DexEncodedMethod> directMethods();
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
index d03e741..d34ba36 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -66,6 +66,26 @@
}
@Override
+ public int numberOfDirectMethods() {
+ return numberOfMethodsMatching(this::belongsToDirectPool);
+ }
+
+ @Override
+ public int numberOfVirtualMethods() {
+ return numberOfMethodsMatching(this::belongsToVirtualPool);
+ }
+
+ private int numberOfMethodsMatching(Predicate<DexEncodedMethod> predicate) {
+ int count = 0;
+ for (DexEncodedMethod method : methodMap.values()) {
+ if (predicate.test(method)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @Override
int size() {
return methodMap.size();
}
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index 34f32ff..1245da9 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -271,7 +271,7 @@
*/
public boolean recordDirectAllocationSite(
DexProgramClass clazz,
- DexEncodedMethod context,
+ ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason,
AppInfo appInfo) {
@@ -285,7 +285,7 @@
Set<DexEncodedMethod> allocationSitesForClass =
classesWithAllocationSiteTracking.computeIfAbsent(
clazz, ignore -> Sets.newIdentityHashSet());
- allocationSitesForClass.add(context);
+ allocationSitesForClass.add(context.getDefinition());
return allocationSitesForClass.size() == 1;
}
if (classesWithoutAllocationSiteTracking.add(clazz)) {
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 4924d0c..88c781c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -3,6 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.origin.Origin;
+
/** Type representing a method definition in the programs compilation unit and its holder. */
public final class ProgramMethod extends DexClassAndMethod {
@@ -10,6 +17,37 @@
super(holder, method);
}
+ public IRCode buildIR(AppView<?> appView) {
+ DexEncodedMethod method = getDefinition();
+ return method.hasCode() ? method.getCode().buildIR(this, appView, getOrigin()) : null;
+ }
+
+ public IRCode buildInliningIR(
+ ProgramMethod context,
+ AppView<?> appView,
+ ValueNumberGenerator valueNumberGenerator,
+ Position callerPosition,
+ Origin origin,
+ MethodProcessor methodProcessor) {
+ Code code = getDefinition().getCode();
+ return code.buildInliningIR(
+ context, this, appView, valueNumberGenerator, callerPosition, origin, methodProcessor);
+ }
+
+ public boolean isStructurallyEqualTo(ProgramMethod other) {
+ return getDefinition() == other.getDefinition() && getHolder() == other.getHolder();
+ }
+
+ public void registerCodeReferences(UseRegistry registry) {
+ Code code = getDefinition().getCode();
+ if (code != null) {
+ if (Log.ENABLED) {
+ Log.verbose(getClass(), "Registering definitions reachable from `%s`.", this);
+ }
+ code.registerCodeReferences(this, registry);
+ }
+ }
+
@Override
public boolean isProgramMethod() {
return true;
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 c632f75..0f63ed1 100644
--- a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
@@ -68,9 +68,9 @@
}
@Override
- void writeMethod(DexEncodedMethod method, PrintStream ps) {
+ void writeMethod(ProgramMethod method, PrintStream ps) {
ps.append("\n");
- ps.append(method.toSmaliString(application.getProguardMap()));
+ ps.append(method.getDefinition().toSmaliString(application.getProguardMap()));
ps.append("\n");
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index b41e8fa..6b03d33 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -12,9 +12,11 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -33,12 +35,13 @@
}
@Override
- public void processNewlyLiveMethod(DexEncodedMethod method) {
- if (method.isClassInitializer()) {
- if (method.getCode().isCfCode()) {
- if (hasJavacClinitAssertionCode(method.getCode().asCfCode())
- || hasKotlincClinitAssertionCode(method)) {
- feedback.setInitializerEnablingJavaVmAssertions(method);
+ public void processNewlyLiveMethod(ProgramMethod method) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (definition.isClassInitializer()) {
+ Code code = definition.getCode();
+ if (code.isCfCode()) {
+ if (hasJavacClinitAssertionCode(code.asCfCode()) || hasKotlincClinitAssertionCode(method)) {
+ feedback.setInitializerEnablingJavaVmAssertions(definition);
}
}
}
@@ -126,9 +129,9 @@
return false;
}
- private boolean hasKotlincClinitAssertionCode(DexEncodedMethod method) {
- if (method.holder() == dexItemFactory.kotlin.assertions.type) {
- CfCode code = method.getCode().asCfCode();
+ private boolean hasKotlincClinitAssertionCode(ProgramMethod method) {
+ if (method.getHolderType() == dexItemFactory.kotlin.assertions.type) {
+ CfCode code = method.getDefinition().getCode().asCfCode();
for (int i = 1; i < code.instructions.size(); i++) {
CfInstruction instruction = code.instructions.get(i - 1);
if (instruction.isInvoke()) {
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
index 8d61294..96b5de8 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/DesugaredLibraryConversionWrapperAnalysis.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.Mode;
import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
@@ -33,7 +34,7 @@
}
@Override
- public void processNewlyLiveMethod(DexEncodedMethod method) {
+ public void processNewlyLiveMethod(ProgramMethod method) {
converter.registerCallbackIfRequired(method);
}
@@ -66,7 +67,7 @@
this.traceInvoke(invokedMethod);
}
- public List<DexEncodedMethod> generateCallbackMethods() {
+ public ProgramMethodSet generateCallbackMethods() {
return converter.generateCallbackMethods();
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 29d7dcc..06f544d 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -5,8 +5,8 @@
package com.android.tools.r8.graph.analysis;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.Timing;
@@ -14,7 +14,7 @@
public abstract class EnqueuerAnalysis {
/** Called when a class is found to be instantiated. */
- public void processNewlyInstantiatedClass(DexProgramClass clazz, DexEncodedMethod context) {}
+ public void processNewlyInstantiatedClass(DexProgramClass clazz, ProgramMethod context) {}
/** Called when a class is found to be live. */
public void processNewlyLiveClass(DexProgramClass clazz, EnqueuerWorklist worklist) {}
@@ -23,7 +23,7 @@
public void processNewlyLiveField(DexEncodedField field) {}
/** Called when a method is found to be live. */
- public void processNewlyLiveMethod(DexEncodedMethod method) {}
+ public void processNewlyLiveMethod(ProgramMethod method) {}
/**
* Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
index 04dbef2..48518f5 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -7,9 +7,9 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -62,7 +62,7 @@
}
@Override
- public void processNewlyInstantiatedClass(DexProgramClass clazz, DexEncodedMethod context) {
+ public void processNewlyInstantiatedClass(DexProgramClass clazz, ProgramMethod context) {
DexType key = clazz.type;
DexType objectType = appView.dexItemFactory().objectType;
if (context == null) {
@@ -74,7 +74,7 @@
// Record that the enclosing class is guaranteed to be initialized at the allocation site.
AppInfoWithClassHierarchy appInfo = appView.appInfo();
- DexType guaranteedToBeInitialized = context.holder();
+ DexType guaranteedToBeInitialized = context.getHolderType();
DexType existingGuaranteedToBeInitialized =
mapping.getOrDefault(key, guaranteedToBeInitialized);
mapping.put(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 75d5423..5e29668 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.BottomValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
@@ -28,11 +29,11 @@
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
@@ -275,11 +276,11 @@
}
}
- public void waveDone(Collection<DexEncodedMethod> wave, OptimizationFeedbackDelayed feedback) {
+ public void waveDone(ProgramMethodSet wave, OptimizationFeedbackDelayed feedback) {
// This relies on the instance initializer info in the method optimization feedback. It is
// therefore important that the optimization info has been flushed in advance.
assert feedback.noUpdatesLeft();
- for (DexEncodedMethod method : wave) {
+ for (ProgramMethod method : wave) {
fieldAccessGraph.markProcessed(method, field -> recordAllFieldPutsProcessed(field, feedback));
objectAllocationGraph.markProcessed(
method, clazz -> recordAllAllocationsSitesProcessed(clazz, feedback));
@@ -328,8 +329,8 @@
});
}
- void markProcessed(DexEncodedMethod method, Consumer<DexEncodedField> allWritesSeenConsumer) {
- List<DexEncodedField> fieldWritesInMethod = fieldWrites.get(method);
+ void markProcessed(ProgramMethod method, Consumer<DexEncodedField> allWritesSeenConsumer) {
+ List<DexEncodedField> fieldWritesInMethod = fieldWrites.get(method.getDefinition());
if (fieldWritesInMethod != null) {
for (DexEncodedField field : fieldWritesInMethod) {
int numberOfPendingFieldWrites = pendingFieldWrites.removeInt(field) - 1;
@@ -366,8 +367,8 @@
}
void markProcessed(
- DexEncodedMethod method, Consumer<DexProgramClass> allAllocationsSitesSeenConsumer) {
- List<DexProgramClass> allocationSitesInMethod = objectAllocations.get(method);
+ ProgramMethod method, Consumer<DexProgramClass> allAllocationsSitesSeenConsumer) {
+ List<DexProgramClass> allocationSitesInMethod = objectAllocations.get(method.getDefinition());
if (allocationSitesInMethod != null) {
for (DexProgramClass type : allocationSitesInMethod) {
int numberOfPendingAllocationSites = pendingObjectAllocations.removeInt(type) - 1;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 5ddacd6..1a6a707 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
@@ -24,6 +25,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -38,7 +40,7 @@
private final Set<DexEncodedField> fieldsOfInterest = Sets.newConcurrentHashSet();
/** Updated concurrently from {@link #processClass(DexProgramClass)}. */
- private final Set<DexEncodedMethod> methodsToReprocess = Sets.newConcurrentHashSet();
+ private final ProgramMethodSet methodsToReprocess = ProgramMethodSet.createConcurrent();
public TrivialFieldAccessReprocessor(
AppView<AppInfoWithLiveness> appView,
@@ -109,11 +111,9 @@
}
private void processClass(DexProgramClass clazz) {
- for (DexEncodedMethod method : clazz.methods()) {
- if (method.hasCode()) {
- method.getCode().registerCodeReferences(method, new TrivialFieldAccessUseRegistry(method));
- }
- }
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::hasCode,
+ method -> method.registerCodeReferences(new TrivialFieldAccessUseRegistry(method)));
}
private static boolean canOptimizeField(
@@ -154,9 +154,9 @@
class TrivialFieldAccessUseRegistry extends UseRegistry {
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
- TrivialFieldAccessUseRegistry(DexEncodedMethod method) {
+ TrivialFieldAccessUseRegistry(ProgramMethod method) {
super(appView.dexItemFactory());
this.method = method;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 3e493b7..4879783 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -4,19 +4,17 @@
package com.android.tools.r8.ir.analysis.proto;
-import static com.google.common.base.Predicates.not;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DefaultUseRegistry;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.IRCodeUtils;
import com.android.tools.r8.ir.code.Instruction;
@@ -24,27 +22,19 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
-import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.DefaultTreePrunerConfiguration;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.TreePrunerConfiguration;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.base.Predicates;
import com.google.common.collect.Sets;
-import java.io.IOException;
-import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
/**
* This optimization is responsible for pruning dead proto extensions.
@@ -173,18 +163,16 @@
timing.end();
}
- private void forEachFindLiteExtensionByNumberMethod(Consumer<DexEncodedMethod> consumer) {
+ private void forEachFindLiteExtensionByNumberMethod(Consumer<ProgramMethod> consumer) {
appView
.appInfo()
.forEachInstantiatedSubType(
references.extensionRegistryLiteType,
- clazz -> {
- for (DexEncodedMethod method : clazz.methods()) {
- if (references.isFindLiteExtensionByNumberMethod(method.method)) {
- consumer.accept(method);
- }
- }
- },
+ clazz ->
+ clazz.forEachProgramMethodMatching(
+ definition ->
+ references.isFindLiteExtensionByNumberMethod(definition.getReference()),
+ consumer::accept),
lambda -> {
assert false;
});
@@ -239,93 +227,4 @@
}
});
}
-
- /** For debugging. */
- public void logRemainingProtoExtensionFields() {
- Predicate<DexField> skip = getSkipPredicate(null);
-
- Set<DexField> remainingProtoExtensionFieldReads = Sets.newIdentityHashSet();
- forEachFindLiteExtensionByNumberMethod(
- method -> {
- Log.info(
- GeneratedExtensionRegistryShrinker.class,
- "Extracting remaining proto extension field reads from method `%s`",
- method.method.toSourceString());
-
- assert method.hasCode();
- method
- .getCode()
- .registerCodeReferences(
- method,
- new DefaultUseRegistry(appView.dexItemFactory()) {
-
- @Override
- public boolean registerStaticFieldRead(DexField field) {
- if (!skip.test(field)) {
- remainingProtoExtensionFieldReads.add(field);
- }
- return true;
- }
- });
- });
-
- Log.info(
- GeneratedExtensionRegistryShrinker.class,
- "Number of remaining proto extension fields: %s",
- remainingProtoExtensionFieldReads.size());
-
- FieldAccessInfoCollection<?> fieldAccessInfoCollection =
- appView.appInfo().getFieldAccessInfoCollection();
- for (DexField field : remainingProtoExtensionFieldReads) {
- StringBuilder message = new StringBuilder(field.toSourceString());
- FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field);
- fieldAccessInfo.forEachReadContext(
- readContext ->
- message
- .append(System.lineSeparator())
- .append("- ")
- .append(readContext.toSourceString()));
- Log.info(GeneratedExtensionRegistryShrinker.class, message.toString());
- }
- }
-
- /**
- * Utility to disable logging for proto extensions fields that are expected to be present in the
- * output.
- *
- * <p>Each proto extension field that is expected to be present in the output can be added to the
- * given file. Then no logs will be emitted for that field.
- *
- * <p>Example: File expected-proto-extensions.txt with lines like this:
- *
- * <pre>
- * foo.bar.SomeClass.someField
- * foo.bar.SomeOtherClass.someOtherField
- * </pre>
- */
- private Predicate<DexField> getSkipPredicate(Path file) {
- if (file != null) {
- try {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- Set<DexField> skipFields =
- FileUtils.readAllLines(file).stream()
- .map(String::trim)
- .filter(not(String::isEmpty))
- .map(
- x -> {
- int separatorIndex = x.lastIndexOf(".");
- return dexItemFactory.createField(
- dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(x.substring(0, separatorIndex))),
- references.generatedExtensionType,
- dexItemFactory.createString(x.substring(separatorIndex + 1)));
- })
- .collect(Collectors.toSet());
- return skipFields::contains;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- return Predicates.alwaysFalse();
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index f073108..a11b346 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -34,7 +35,6 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.inliner.FixedInliningReasonStrategy;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.PredicateSet;
import com.android.tools.r8.utils.ThreadUtils;
@@ -54,7 +54,7 @@
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final ProtoReferences references;
- private final Map<DexProgramClass, DexEncodedMethod> builders = new IdentityHashMap<>();
+ private final Map<DexProgramClass, ProgramMethod> builders = new IdentityHashMap<>();
GeneratedMessageLiteBuilderShrinker(
AppView<? extends AppInfoWithClassHierarchy> appView, ProtoReferences references) {
@@ -64,11 +64,12 @@
/** Returns true if an action was deferred. */
public boolean deferDeadProtoBuilders(
- DexProgramClass clazz, DexEncodedMethod context, BooleanSupplier register) {
- if (references.isDynamicMethod(context) && references.isGeneratedMessageLiteBuilder(clazz)) {
+ DexProgramClass clazz, ProgramMethod method, BooleanSupplier register) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (references.isDynamicMethod(definition) && references.isGeneratedMessageLiteBuilder(clazz)) {
if (register.getAsBoolean()) {
- assert builders.getOrDefault(clazz, context) == context;
- builders.put(clazz, context);
+ assert !builders.containsKey(clazz) || builders.get(clazz).getDefinition() == definition;
+ builders.put(clazz, method);
return true;
}
}
@@ -104,12 +105,11 @@
private void removeDeadBuilderReferencesFromDynamicMethod(
AppView<AppInfoWithLiveness> appView,
- DexEncodedMethod dynamicMethod,
+ ProgramMethod dynamicMethod,
IRConverter converter,
CodeRewriter codeRewriter,
SwitchCaseAnalyzer switchCaseAnalyzer) {
- Origin origin = appView.appInfo().originFor(dynamicMethod.holder());
- IRCode code = dynamicMethod.buildIR(appView, origin);
+ IRCode code = dynamicMethod.buildIR(appView);
codeRewriter.rewriteSwitch(code, switchCaseAnalyzer);
converter.removeDeadCodeAndFinalizeIR(
dynamicMethod, code, OptimizationFeedbackSimple.getInstance(), Timing.empty());
@@ -132,7 +132,7 @@
if (node != null) {
List<Node> calleesToBeRemoved = new ArrayList<>();
for (Node callee : node.getCalleesWithDeterministicOrder()) {
- if (references.isDynamicMethodBridge(callee.method)) {
+ if (references.isDynamicMethodBridge(callee.getMethod())) {
calleesToBeRemoved.add(callee);
}
}
@@ -143,7 +143,7 @@
}
public void inlineCallsToDynamicMethod(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
EnumValueOptimizer enumValueOptimizer,
OptimizationFeedback feedback,
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 4414507..7d74c63 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
@@ -9,10 +9,9 @@
import static com.android.tools.r8.ir.analysis.proto.ProtoUtils.setObjectsValueForMessageInfoConstructionInvoke;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoMessageInfo;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoObject;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -68,8 +67,9 @@
this.stringType = TypeElement.stringClassType(appView, Nullability.definitelyNotNull());
}
- public void run(DexEncodedMethod method, IRCode code) {
- if (references.isDynamicMethod(method.method)) {
+ public void run(IRCode code) {
+ ProgramMethod method = code.context();
+ if (references.isDynamicMethod(method.getReference())) {
rewriteDynamicMethod(method, code);
}
}
@@ -89,19 +89,19 @@
timing.end();
}
- private void forEachDynamicMethod(Consumer<DexEncodedMethod> consumer) {
+ private void forEachDynamicMethod(Consumer<ProgramMethod> consumer) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
appView
.appInfo()
.forEachInstantiatedSubType(
references.generatedMessageLiteType,
clazz -> {
- DexMethod dynamicMethod =
+ DexMethod dynamicMethodReference =
dexItemFactory.createMethod(
clazz.type, references.dynamicMethodProto, references.dynamicMethodName);
- DexEncodedMethod encodedDynamicMethod = clazz.lookupVirtualMethod(dynamicMethod);
- if (encodedDynamicMethod != null) {
- consumer.accept(encodedDynamicMethod);
+ ProgramMethod dynamicMethod = clazz.lookupProgramMethod(dynamicMethodReference);
+ if (dynamicMethod != null) {
+ consumer.accept(dynamicMethod);
}
},
lambda -> {
@@ -117,12 +117,7 @@
* <p>NOTE: This is work in progress. Understanding the full semantics of the arguments passed to
* newMessageInfo is still pending.
*/
- private void rewriteDynamicMethod(DexEncodedMethod method, IRCode code) {
- DexClass context = appView.definitionFor(method.holder());
- if (context == null || !context.isProgramClass()) {
- return;
- }
-
+ private void rewriteDynamicMethod(ProgramMethod method, IRCode code) {
InvokeMethod newMessageInfoInvoke = getNewMessageInfoInvoke(code, references);
if (newMessageInfoInvoke != null) {
Value infoValue =
@@ -131,11 +126,10 @@
getObjectsValueFromMessageInfoConstructionInvoke(newMessageInfoInvoke, references);
// Decode the arguments passed to newMessageInfo().
- ProtoMessageInfo protoMessageInfo = decoder.run(method, context, infoValue, objectsValue);
+ ProtoMessageInfo protoMessageInfo = decoder.run(method, infoValue, objectsValue);
if (protoMessageInfo != null) {
// Rewrite the arguments to newMessageInfo().
- rewriteArgumentsToNewMessageInfo(
- method, code, newMessageInfoInvoke, infoValue, protoMessageInfo);
+ rewriteArgumentsToNewMessageInfo(code, newMessageInfoInvoke, infoValue, protoMessageInfo);
// Ensure that the definition of the original `objects` value is removed.
IRCodeUtils.removeArrayAndTransitiveInputsIfNotUsed(code, objectsValue.definition);
@@ -147,13 +141,12 @@
}
private void rewriteArgumentsToNewMessageInfo(
- DexEncodedMethod method,
IRCode code,
InvokeMethod newMessageInfoInvoke,
Value infoValue,
ProtoMessageInfo protoMessageInfo) {
rewriteInfoArgumentToNewMessageInfo(code, infoValue, protoMessageInfo);
- rewriteObjectsArgumentToNewMessageInfo(method, code, newMessageInfoInvoke, protoMessageInfo);
+ rewriteObjectsArgumentToNewMessageInfo(code, newMessageInfoInvoke, protoMessageInfo);
}
private void rewriteInfoArgumentToNewMessageInfo(
@@ -165,7 +158,6 @@
}
private void rewriteObjectsArgumentToNewMessageInfo(
- DexEncodedMethod method,
IRCode code,
InvokeMethod newMessageInfoInvoke,
ProtoMessageInfo protoMessageInfo) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
index 79dea35..d5fdc33 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoEnqueuerUseRegistry.java
@@ -5,10 +5,9 @@
package com.android.tools.r8.ir.analysis.proto;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoEnqueuerExtension;
import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
import com.android.tools.r8.shaking.Enqueuer;
@@ -21,11 +20,8 @@
private final ProtoReferences references;
public ProtoEnqueuerUseRegistry(
- AppView<?> appView,
- DexProgramClass currentHolder,
- DexEncodedMethod currentMethod,
- Enqueuer enqueuer) {
- super(appView, currentHolder, currentMethod, enqueuer);
+ AppView<?> appView, ProgramMethod currentMethod, Enqueuer enqueuer) {
+ super(appView, currentMethod, enqueuer);
this.references = appView.protoShrinker().references;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
index 1321984..ca4ca1e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoInliningReasonStrategy.java
@@ -5,9 +5,8 @@
package com.android.tools.r8.ir.analysis.proto;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.proto.ProtoReferences.MethodToInvokeMembers;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -35,9 +34,8 @@
@Override
public Reason computeInliningReason(
- InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
- DexProgramClass enclosingClass = appView.definitionFor(context.holder()).asProgramClass();
- if (references.isAbstractGeneratedMessageLiteBuilder(enclosingClass)
+ InvokeMethod invoke, ProgramMethod target, ProgramMethod context) {
+ if (references.isAbstractGeneratedMessageLiteBuilder(context.getHolder())
&& invoke.isInvokeSuper()) {
// Aggressively inline invoke-super calls inside the GeneratedMessageLite builders. Such
// instructions prohibit inlining of the enclosing method into other contexts, and therefore
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
index 014ab85..c2c9a50 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/ProtoReferences.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Value;
public class ProtoReferences {
@@ -43,6 +44,7 @@
public final DexProto dynamicMethodProto;
public final DexProto findLiteExtensionByNumberProto;
+ public final DexMethod dynamicMethod;
public final DexMethod newMessageInfoMethod;
public final DexMethod rawMessageInfoConstructor;
@@ -80,6 +82,8 @@
factory.createProto(generatedExtensionType, messageLiteType, factory.intType);
// Methods.
+ dynamicMethod =
+ factory.createMethod(generatedMessageLiteType, dynamicMethodProto, dynamicMethodName);
newMessageInfoMethod =
factory.createMethod(
generatedMessageLiteType,
@@ -114,6 +118,10 @@
return isDynamicMethod(encodedMethod.method);
}
+ public boolean isDynamicMethod(ProgramMethod method) {
+ return isDynamicMethod(method.getReference());
+ }
+
public boolean isDynamicMethodBridge(DexMethod method) {
return method == generatedMessageLiteMethods.dynamicMethodBridgeMethod;
}
@@ -122,6 +130,10 @@
return isDynamicMethodBridge(method.method);
}
+ public boolean isDynamicMethodBridge(ProgramMethod method) {
+ return isDynamicMethodBridge(method.getReference());
+ }
+
public boolean isFindLiteExtensionByNumberMethod(DexMethod method) {
return method.proto == findLiteExtensionByNumberProto
&& method.name.startsWith(findLiteExtensionByNumberName)
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 6d404cf..e4741d9 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
@@ -7,12 +7,11 @@
import static com.android.tools.r8.ir.analysis.proto.ProtoUtils.getInfoValueFromMessageInfoConstructionInvoke;
import static com.android.tools.r8.ir.analysis.proto.ProtoUtils.getObjectsValueFromMessageInfoConstructionInvoke;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.proto.schema.DeadProtoFieldObject;
import com.android.tools.r8.ir.analysis.proto.schema.LiveProtoFieldObject;
import com.android.tools.r8.ir.analysis.proto.schema.ProtoFieldInfo;
@@ -76,16 +75,14 @@
this.references = references;
}
- public ProtoMessageInfo run(
- DexEncodedMethod dynamicMethod, DexClass context, InvokeMethod invoke) {
+ public ProtoMessageInfo run(ProgramMethod dynamicMethod, InvokeMethod invoke) {
assert references.isMessageInfoConstructionMethod(invoke.getInvokedMethod());
Value infoValue = getInfoValueFromMessageInfoConstructionInvoke(invoke, references);
Value objectsValue = getObjectsValueFromMessageInfoConstructionInvoke(invoke, references);
- return run(dynamicMethod, context, infoValue, objectsValue);
+ return run(dynamicMethod, infoValue, objectsValue);
}
- public ProtoMessageInfo run(
- DexEncodedMethod dynamicMethod, DexClass context, Value infoValue, Value objectsValue) {
+ public ProtoMessageInfo run(ProgramMethod dynamicMethod, Value infoValue, Value objectsValue) {
try {
ProtoMessageInfo.Builder builder = ProtoMessageInfo.builder(dynamicMethod);
ThrowingIntIterator<InvalidRawMessageInfoException> infoIterator =
@@ -125,13 +122,13 @@
for (int i = 0; i < numberOfOneOfObjects; i++) {
ProtoObject oneOfObject =
createProtoObject(
- objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context);
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), dynamicMethod);
if (!oneOfObject.isProtoFieldObject()) {
throw new InvalidRawMessageInfoException();
}
ProtoObject oneOfCaseObject =
createProtoObject(
- objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context);
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), dynamicMethod);
if (!oneOfCaseObject.isProtoFieldObject()) {
throw new InvalidRawMessageInfoException();
}
@@ -142,7 +139,7 @@
for (int i = 0; i < numberOfHasBitsObjects; i++) {
ProtoObject hasBitsObject =
createProtoObject(
- objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), context);
+ objectIterator.computeNextIfAbsent(this::invalidObjectsFailure), dynamicMethod);
if (!hasBitsObject.isProtoFieldObject()) {
throw new InvalidRawMessageInfoException();
}
@@ -168,7 +165,7 @@
try {
List<ProtoObject> objects = new ArrayList<>(numberOfObjects);
for (Value value : objectIterator.take(numberOfObjects)) {
- objects.add(createProtoObject(value, context));
+ objects.add(createProtoObject(value, dynamicMethod));
}
builder.addField(new ProtoFieldInfo(fieldNumber, fieldType, auxData, objects));
} catch (NoSuchElementException e) {
@@ -189,7 +186,7 @@
}
}
- private ProtoObject createProtoObject(Value value, DexClass context)
+ private ProtoObject createProtoObject(Value value, ProgramMethod context)
throws InvalidRawMessageInfoException {
Value root = value.getAliasedValue();
if (!root.isPhi()) {
@@ -199,13 +196,14 @@
return new ProtoTypeObject(constClass.getValue());
} else if (definition.isConstString()) {
ConstString constString = definition.asConstString();
- DexField field = context.lookupUniqueInstanceFieldWithName(constString.getValue());
+ DexField field =
+ context.getHolder().lookupUniqueInstanceFieldWithName(constString.getValue());
if (field != null) {
return new LiveProtoFieldObject(field);
}
// This const-string refers to a field that no longer exists. In this case, we create a
// special dead-object instead of failing with an InvalidRawMessageInfoException below.
- return new DeadProtoFieldObject(context.type, constString.getValue());
+ return new DeadProtoFieldObject(context.getHolderType(), constString.getValue());
} else if (definition.isDexItemBasedConstString()) {
DexItemBasedConstString constString = definition.asDexItemBasedConstString();
DexReference reference = constString.getItem();
@@ -214,13 +212,13 @@
&& nameComputationInfo.isFieldNameComputationInfo()
&& nameComputationInfo.asFieldNameComputationInfo().isForFieldName()) {
DexField field = reference.asDexField();
- DexEncodedField encodedField = context.lookupInstanceField(field);
+ DexEncodedField encodedField = context.getHolder().lookupInstanceField(field);
if (encodedField != null) {
return new LiveProtoFieldObject(field);
}
// This const-string refers to a field that no longer exists. In this case, we create a
// special dead-object instead of failing with an InvalidRawMessageInfoException below.
- return new DeadProtoFieldObject(context.type, field.name);
+ return new DeadProtoFieldObject(context.getHolderType(), field.name);
}
} else if (definition.isInvokeStatic()) {
InvokeStatic invoke = definition.asInvokeStatic();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index d6d2990..8001121 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -8,13 +8,13 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
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.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteShrinker;
import com.android.tools.r8.ir.analysis.proto.ProtoEnqueuerUseRegistry;
@@ -38,6 +38,7 @@
import com.android.tools.r8.utils.BitUtils;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.IdentityHashMap;
@@ -79,7 +80,7 @@
Sets.newIdentityHashSet();
// The findLiteExtensionByNumber() methods that have become live since the last fixpoint.
- private final Set<DexEncodedMethod> findLiteExtensionByNumberMethods = Sets.newIdentityHashSet();
+ private final ProgramMethodSet findLiteExtensionByNumberMethods = ProgramMethodSet.create();
// Mapping from extension container types to the extensions for that type.
private final Map<DexType, Set<DexType>> extensionGraph = new IdentityHashMap<>();
@@ -107,7 +108,7 @@
assert clazz.type == references.extendableMessageType;
return;
}
- DexEncodedMethod dynamicMethod = clazz.lookupVirtualMethod(references::isDynamicMethod);
+ ProgramMethod dynamicMethod = clazz.lookupProgramMethod(references.dynamicMethod);
if (dynamicMethod != null) {
worklist.enqueueMarkInstantiatedAction(
clazz,
@@ -125,49 +126,39 @@
* ProtoMessageInfo} object, and create a mapping from the holder to it.
*/
@Override
- public void processNewlyLiveMethod(DexEncodedMethod encodedMethod) {
- if (references.isFindLiteExtensionByNumberMethod(encodedMethod.method)) {
- findLiteExtensionByNumberMethods.add(encodedMethod);
+ public void processNewlyLiveMethod(ProgramMethod method) {
+ if (references.isFindLiteExtensionByNumberMethod(method.getReference())) {
+ findLiteExtensionByNumberMethods.add(method);
return;
}
- if (!references.isDynamicMethod(encodedMethod)) {
+ if (!references.isDynamicMethod(method)) {
return;
}
- DexType holder = encodedMethod.holder();
- if (seenButNotLiveProtos.containsKey(holder)) {
+ DexType holderType = method.getHolderType();
+ if (seenButNotLiveProtos.containsKey(holderType)) {
// The proto is now live instead of dead.
- liveProtos.put(holder, seenButNotLiveProtos.remove(holder));
+ liveProtos.put(holderType, seenButNotLiveProtos.remove(holderType));
return;
}
// Since this dynamicMethod() only becomes live once, and it has just become live, it must be
// the case that the proto is not already live.
- assert !liveProtos.containsKey(holder);
- createProtoMessageInfoFromDynamicMethod(encodedMethod, liveProtos);
+ assert !liveProtos.containsKey(holderType);
+ createProtoMessageInfoFromDynamicMethod(method, liveProtos);
}
private void createProtoMessageInfoFromDynamicMethod(
- DexEncodedMethod dynamicMethod, Map<DexType, ProtoMessageInfo> protos) {
- DexType holder = dynamicMethod.holder();
+ ProgramMethod dynamicMethod, Map<DexType, ProtoMessageInfo> protos) {
+ DexType holder = dynamicMethod.getHolderType();
assert !protos.containsKey(holder);
- DexClass context = appView.definitionFor(holder);
- if (context == null || !context.isProgramClass()) {
- // TODO(b/112437944): What if a proto message references a proto message on the classpath or
- // library path? We should treat them as having a map/required field to be conservative.
- assert false; // Should generally not happen.
- return;
- }
-
- IRCode code = dynamicMethod.buildIR(appView, context.origin);
+ IRCode code = dynamicMethod.buildIR(appView);
InvokeMethod newMessageInfoInvoke =
GeneratedMessageLiteShrinker.getNewMessageInfoInvoke(code, references);
ProtoMessageInfo protoMessageInfo =
- newMessageInfoInvoke != null
- ? decoder.run(dynamicMethod, context, newMessageInfoInvoke)
- : null;
+ newMessageInfoInvoke != null ? decoder.run(dynamicMethod, newMessageInfoInvoke) : null;
protos.put(holder, protoMessageInfo);
}
@@ -221,13 +212,13 @@
collectExtensionFields()
.forEach(
(clazz, extensionFields) -> {
- DexEncodedMethod clinit = clazz.getClassInitializer();
+ ProgramMethod clinit = clazz.getProgramClassInitializer();
if (clinit == null) {
assert false; // Should generally not happen.
return;
}
- IRCode code = clinit.buildIR(appView, appView.appInfo().originFor(clazz.type));
+ IRCode code = clinit.buildIR(appView);
Map<DexEncodedField, StaticPut> uniqueStaticPuts =
IRCodeUtils.findUniqueStaticPuts(appView, code, extensionFields);
for (DexEncodedField extensionField : extensionFields) {
@@ -251,10 +242,8 @@
*/
private Map<DexProgramClass, Set<DexEncodedField>> collectExtensionFields() {
Map<DexProgramClass, Set<DexEncodedField>> extensionFieldsByClass = new IdentityHashMap<>();
- for (DexEncodedMethod findLiteExtensionByNumberMethod : findLiteExtensionByNumberMethods) {
- IRCode code =
- findLiteExtensionByNumberMethod.buildIR(
- appView, appView.appInfo().originFor(findLiteExtensionByNumberMethod.holder()));
+ for (ProgramMethod findLiteExtensionByNumberMethod : findLiteExtensionByNumberMethods) {
+ IRCode code = findLiteExtensionByNumberMethod.buildIR(appView);
for (BasicBlock block : code.blocks(BasicBlock::isReturnBlock)) {
Value returnValue = block.exit().asReturn().returnValue().getAliasedValue();
if (returnValue.isPhi()) {
@@ -364,9 +353,7 @@
continue;
}
- DexEncodedMethod dynamicMethod = protoMessageInfo.getDynamicMethod();
- DexProgramClass clazz = appView.definitionFor(dynamicMethod.holder()).asProgramClass();
-
+ ProgramMethod dynamicMethod = protoMessageInfo.getDynamicMethod();
for (ProtoFieldInfo protoFieldInfo : protoMessageInfo.getFields()) {
DexEncodedField valueStorage = protoFieldInfo.getValueStorage(appView, protoMessageInfo);
if (valueStorage == null) {
@@ -390,7 +377,7 @@
// written such that we cannot optimize any field reads or writes.
enqueuer.registerReflectiveFieldAccess(valueStorage.field, dynamicMethod);
worklist.enqueueMarkReachableFieldAction(
- clazz, valueStorage, KeepReason.reflectiveUseIn(dynamicMethod));
+ dynamicMethod.getHolder(), valueStorage, KeepReason.reflectiveUseIn(dynamicMethod));
valueStorageIsLive = true;
} else {
valueStorageIsLive = false;
@@ -438,10 +425,13 @@
if (newlyLiveField != null) {
// Mark hazzer and one-of proto fields as read from dynamicMethod() if they are written in
// the app. This is needed to ensure that field writes are not removed from the app.
- DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer();
+ ProgramMethod defaultInitializer =
+ dynamicMethod.getHolder().getProgramDefaultInitializer();
assert defaultInitializer != null;
Predicate<DexEncodedMethod> neitherDefaultConstructorNorDynamicMethod =
- writer -> writer != defaultInitializer && writer != dynamicMethod;
+ writer ->
+ writer != defaultInitializer.getDefinition()
+ && writer != dynamicMethod.getDefinition();
if (enqueuer.isFieldWrittenInMethodSatisfying(
newlyLiveField, neitherDefaultConstructorNorDynamicMethod)) {
enqueuer.registerReflectiveFieldRead(newlyLiveField.field, dynamicMethod);
@@ -451,7 +441,9 @@
// dynamicMethod().
if (enqueuer.registerReflectiveFieldWrite(newlyLiveField.field, dynamicMethod)) {
worklist.enqueueMarkReachableFieldAction(
- clazz, newlyLiveField, KeepReason.reflectiveUseIn(dynamicMethod));
+ dynamicMethod.getHolder(),
+ newlyLiveField,
+ KeepReason.reflectiveUseIn(dynamicMethod));
}
}
}
@@ -467,8 +459,8 @@
continue;
}
- DexEncodedMethod dynamicMethod = protoMessageInfo.getDynamicMethod();
- if (!dynamicMethodsWithTracedProtoObjects.add(dynamicMethod)) {
+ ProgramMethod dynamicMethod = protoMessageInfo.getDynamicMethod();
+ if (!dynamicMethodsWithTracedProtoObjects.add(dynamicMethod.getDefinition())) {
continue;
}
@@ -526,13 +518,14 @@
return;
}
- DexClass clazz = appView.definitionFor(encodedOneOfCaseField.holder());
- if (clazz == null || !clazz.isProgramClass()) {
+ DexProgramClass clazz =
+ asProgramClassOrNull(appView.definitionFor(encodedOneOfCaseField.holder()));
+ if (clazz == null) {
assert false;
return;
}
- DexEncodedMethod dynamicMethod = clazz.lookupVirtualMethod(references::isDynamicMethod);
+ ProgramMethod dynamicMethod = clazz.lookupProgramMethod(references.dynamicMethod);
if (dynamicMethod == null) {
assert false;
return;
@@ -651,13 +644,13 @@
return seenButNotLiveProtos.get(type);
}
- DexClass clazz = appView.definitionFor(type);
- if (clazz == null || !clazz.isProgramClass()) {
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
+ if (clazz == null) {
seenButNotLiveProtos.put(type, null);
return null;
}
- DexEncodedMethod dynamicMethod = clazz.lookupVirtualMethod(references::isDynamicMethod);
+ ProgramMethod dynamicMethod = clazz.lookupProgramMethod(references.dynamicMethod);
if (dynamicMethod == null) {
seenButNotLiveProtos.put(type, null);
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
index f026295..28de572 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoMessageInfo.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.analysis.proto.schema;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.proto.ProtoUtils;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
@@ -22,7 +22,7 @@
public static class Builder {
- private final DexEncodedMethod dynamicMethod;
+ private final ProgramMethod dynamicMethod;
private int flags;
@@ -30,7 +30,7 @@
private LinkedList<ProtoFieldObject> hasBitsObjects;
private LinkedList<ProtoOneOfObjectPair> oneOfObjects;
- private Builder(DexEncodedMethod dynamicMethod) {
+ private Builder(ProgramMethod dynamicMethod) {
this.dynamicMethod = dynamicMethod;
}
@@ -171,7 +171,7 @@
}
}
- private final DexEncodedMethod dynamicMethod;
+ private final ProgramMethod dynamicMethod;
private final int flags;
private final LinkedList<ProtoFieldInfo> fields;
@@ -179,7 +179,7 @@
private final LinkedList<ProtoOneOfObjectPair> oneOfObjects;
private ProtoMessageInfo(
- DexEncodedMethod dynamicMethod,
+ ProgramMethod dynamicMethod,
int flags,
LinkedList<ProtoFieldInfo> fields,
LinkedList<ProtoFieldObject> hasBitsObjects,
@@ -191,7 +191,7 @@
this.oneOfObjects = oneOfObjects;
}
- public static ProtoMessageInfo.Builder builder(DexEncodedMethod dynamicMethod) {
+ public static ProtoMessageInfo.Builder builder(ProgramMethod dynamicMethod) {
return new ProtoMessageInfo.Builder(dynamicMethod);
}
@@ -199,7 +199,7 @@
return ProtoUtils.isProto2(flags);
}
- public DexEncodedMethod getDynamicMethod() {
+ public ProgramMethod getDynamicMethod() {
return dynamicMethod;
}
@@ -220,7 +220,7 @@
}
public DexType getType() {
- return dynamicMethod.holder();
+ return dynamicMethod.getHolderType();
}
public boolean hasFields() {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index b45ec56..76213c6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstClass;
import com.android.tools.r8.ir.code.IRCode;
@@ -79,16 +80,15 @@
}
@Override
- public boolean isMaterializableInContext(AppView<AppInfoWithLiveness> appView, DexType context) {
+ public boolean isMaterializableInContext(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isClassType()) {
DexClass clazz = appView.definitionFor(type);
return clazz != null
&& clazz.isResolvable(appView)
&& AccessControl.isClassAccessible(
- clazz,
- appView.definitionFor(context).asProgramClass(),
- appView.options().featureSplitConfiguration)
+ clazz, context.getHolder(), appView.options().featureSplitConfiguration)
.isTrue();
}
assert baseType.isPrimitiveType();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 46261f5..7bccd30 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.IRCode;
@@ -77,11 +78,12 @@
}
@Override
- public boolean isMaterializableInContext(AppView<AppInfoWithLiveness> appView, DexType context) {
+ public boolean isMaterializableInContext(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
return AccessControl.isFieldAccessible(
appView.appInfo().resolveField(field),
appView.definitionForHolder(field),
- appView.definitionFor(context).asProgramClass(),
+ context.getHolder(),
appView.appInfo())
.isTrue();
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index 1982181..67a0858 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -7,8 +7,8 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
@@ -80,7 +80,8 @@
}
@Override
- public boolean isMaterializableInContext(AppView<AppInfoWithLiveness> appView, DexType context) {
+ public boolean isMaterializableInContext(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
index 01f80cc..457d49b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstString;
@@ -81,7 +81,8 @@
}
@Override
- public boolean isMaterializableInContext(AppView<AppInfoWithLiveness> appView, DexType context) {
+ public boolean isMaterializableInContext(
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
index 61426a0..f0425b0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleValue.java
@@ -6,8 +6,8 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
@@ -41,7 +41,7 @@
TypeAndLocalInfoSupplier info);
public abstract boolean isMaterializableInContext(
- AppView<AppInfoWithLiveness> appView, DexType context);
+ AppView<AppInfoWithLiveness> appView, ProgramMethod context);
public abstract boolean isMaterializableInAllContexts(AppView<?> appView);
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 53b9336..a37e369 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.analysis.TypeChecker;
import com.android.tools.r8.ir.analysis.ValueMayDependOnEnvironmentAnalysis;
@@ -104,7 +105,7 @@
// use odd instruction numbers for the insertion of moves during spilling.
public static final int INSTRUCTION_NUMBER_DELTA = 2;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
public LinkedList<BasicBlock> blocks;
public final ValueNumberGenerator valueNumberGenerator;
@@ -124,7 +125,7 @@
public IRCode(
InternalOptions options,
- DexEncodedMethod method,
+ ProgramMethod method,
LinkedList<BasicBlock> blocks,
ValueNumberGenerator valueNumberGenerator,
IRMetadata metadata,
@@ -145,10 +146,15 @@
return metadata;
}
- public DexEncodedMethod method() {
+ public ProgramMethod context() {
return method;
}
+ @Deprecated
+ public DexEncodedMethod method() {
+ return method.getDefinition();
+ }
+
public BasicBlock entryBlock() {
return blocks.getFirst();
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 78d3a69..6c9fb6f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
@@ -78,6 +79,11 @@
public abstract DexEncodedMethod lookupSingleTarget(
AppView<?> appView, DexType invocationContext);
+ public final ProgramMethod lookupSingleProgramTarget(AppView<?> appView, ProgramMethod context) {
+ DexEncodedMethod singleTarget = lookupSingleTarget(appView, context.getHolderType());
+ return singleTarget != null ? singleTarget.asProgramMethod(appView) : null;
+ }
+
// TODO(b/140204899): Refactor lookup methods to be defined in a single place.
public Collection<DexEncodedMethod> lookupTargets(
AppView<AppInfoWithLiveness> appView, DexType invocationContext) {
@@ -135,7 +141,7 @@
}
public abstract InlineAction computeInlining(
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
DefaultInliningOracle decider,
ClassInitializationAnalysis classInitializationAnalysis,
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index 5ed1539..00ffbe1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -5,10 +5,10 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -43,7 +43,7 @@
@Override
public final InlineAction computeInlining(
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
DefaultInliningOracle decider,
ClassInitializationAnalysis classInitializationAnalysis,
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index 41b1124..8d46da1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -139,7 +140,7 @@
@Override
public InlineAction computeInlining(
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
DefaultInliningOracle decider,
ClassInitializationAnalysis classInitializationAnalysis,
@@ -148,7 +149,7 @@
if (singleTarget != null) {
throw new Unreachable(
"Unexpected invoke-polymorphic with `"
- + singleTarget.method.toSourceString()
+ + singleTarget.toSourceString()
+ "` as single target");
}
throw new Unreachable("Unexpected attempt to inline invoke that does not have a single target");
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 9a9f727..5ea6e46 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
@@ -130,7 +131,7 @@
@Override
public InlineAction computeInlining(
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
DefaultInliningOracle decider,
ClassInitializationAnalysis classInitializationAnalysis,
diff --git a/src/main/java/com/android/tools/r8/ir/code/Position.java b/src/main/java/com/android/tools/r8/ir/code/Position.java
index 2b05e0c..6ed94b4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Position.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Position.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.ir.code;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.ProgramMethod;
import com.google.common.annotations.VisibleForTesting;
import java.util.Objects;
@@ -79,15 +79,15 @@
}
public static Position getPositionForInlining(
- AppView<?> appView, InvokeMethod invoke, DexEncodedMethod context) {
+ AppView<?> appView, InvokeMethod invoke, ProgramMethod context) {
Position position = invoke.getPosition();
if (position.method == null) {
assert position.isNone();
- position = Position.noneWithMethod(context.method, null);
+ position = Position.noneWithMethod(context.getReference(), null);
}
assert position.callerPosition == null
|| position.getOutermostCaller().method
- == appView.graphLense().getOriginalMethodSignature(context.method);
+ == appView.graphLense().getOriginalMethodSignature(context.getReference());
return position;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index 6f3bf92..a5842de 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -6,9 +6,11 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraphBuilderBase.CycleEliminator.CycleEliminationResult;
import com.android.tools.r8.ir.conversion.CallSiteInformation.CallGraphBasedCallSiteInformation;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.Set;
@@ -38,7 +40,7 @@
public static Node[] EMPTY_ARRAY = {};
- public final DexEncodedMethod method;
+ private final ProgramMethod method;
private int numberOfCallSites = 0;
// Outgoing calls from this method.
@@ -55,7 +57,7 @@
// by the current method).
private final Set<Node> writers = new TreeSet<>();
- public Node(DexEncodedMethod method) {
+ public Node(ProgramMethod method) {
this.method = method;
}
@@ -201,14 +203,16 @@
@Override
public int compareTo(Node other) {
- return method.method.slowCompareTo(other.method.method);
+ return getProgramMethod()
+ .getReference()
+ .slowCompareTo(other.getProgramMethod().getReference());
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MethodNode for: ");
- builder.append(method.toSourceString());
+ builder.append(getProgramMethod().toSourceString());
builder.append(" (");
builder.append(callees.size());
builder.append(" callees, ");
@@ -222,7 +226,7 @@
builder.append(System.lineSeparator());
for (Node call : callees) {
builder.append(" ");
- builder.append(call.method.toSourceString());
+ builder.append(call.getProgramMethod().toSourceString());
builder.append(System.lineSeparator());
}
}
@@ -231,12 +235,20 @@
builder.append(System.lineSeparator());
for (Node caller : callers) {
builder.append(" ");
- builder.append(caller.method.toSourceString());
+ builder.append(caller.getProgramMethod().toSourceString());
builder.append(System.lineSeparator());
}
}
return builder.toString();
}
+
+ public DexEncodedMethod getMethod() {
+ return method.getDefinition();
+ }
+
+ public ProgramMethod getProgramMethod() {
+ return method;
+ }
}
final Set<Node> nodes;
@@ -266,22 +278,22 @@
return nodes.isEmpty();
}
- public Set<DexEncodedMethod> extractLeaves() {
+ public ProgramMethodSet extractLeaves() {
return extractNodes(Node::isLeaf, Node::cleanCallersAndReadersForRemoval);
}
- public Set<DexEncodedMethod> extractRoots() {
+ public ProgramMethodSet extractRoots() {
return extractNodes(Node::isRoot, Node::cleanCalleesAndWritersForRemoval);
}
- private Set<DexEncodedMethod> extractNodes(Predicate<Node> predicate, Consumer<Node> clean) {
- Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
+ private ProgramMethodSet extractNodes(Predicate<Node> predicate, Consumer<Node> clean) {
+ ProgramMethodSet result = ProgramMethodSet.create();
Set<Node> removed = Sets.newIdentityHashSet();
Iterator<Node> nodeIterator = nodes.iterator();
while (nodeIterator.hasNext()) {
Node node = nodeIterator.next();
if (predicate.test(node)) {
- result.add(node.method);
+ result.add(node.getProgramMethod());
nodeIterator.remove();
removed.add(node);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
index 5b94efb..e6f7cb6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
@@ -4,12 +4,14 @@
package com.android.tools.r8.ir.conversion;
+import static com.google.common.base.Predicates.alwaysTrue;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
-import com.google.common.base.Predicates;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -25,21 +27,18 @@
}
private void processClass(DexProgramClass clazz) {
- clazz.forEachMethod(this::processMethod);
+ clazz.forEachProgramMethodMatching(DexEncodedMethod::hasCode, this::processMethod);
}
- private void processMethod(DexEncodedMethod method) {
- if (method.hasCode()) {
- method.registerCodeReferences(
- new InvokeExtractor(getOrCreateNode(method), Predicates.alwaysTrue()));
- }
+ private void processMethod(ProgramMethod method) {
+ method.registerCodeReferences(new InvokeExtractor(getOrCreateNode(method), alwaysTrue()));
}
@Override
boolean verifyAllMethodsWithCodeExists() {
for (DexProgramClass clazz : appView.appInfo().classes()) {
for (DexEncodedMethod method : clazz.methods()) {
- assert !method.hasCode() || nodes.get(method.method) != null;
+ assert method.hasCode() == (nodes.get(method.method) != null);
}
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 49ea06a..e6bd8bf 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -19,6 +20,7 @@
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.Invoke;
@@ -26,15 +28,13 @@
import com.android.tools.r8.ir.conversion.CallGraphBuilderBase.CycleEliminator.CycleEliminationResult;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableSet;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
-import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -52,7 +52,7 @@
final AppView<AppInfoWithLiveness> appView;
private final FieldAccessInfoCollection<?> fieldAccessInfoCollection;
final Map<DexMethod, Node> nodes = new IdentityHashMap<>();
- private final Map<DexMethod, Set<DexEncodedMethod>> possibleTargetsCache =
+ private final Map<DexMethod, ProgramMethodSet> possibleProgramTargetsCache =
new ConcurrentHashMap<>();
CallGraphBuilderBase(AppView<AppInfoWithLiveness> appView) {
@@ -97,9 +97,9 @@
return true;
}
- Node getOrCreateNode(DexEncodedMethod method) {
+ Node getOrCreateNode(ProgramMethod method) {
synchronized (nodes) {
- return nodes.computeIfAbsent(method.method, ignore -> new Node(method));
+ return nodes.computeIfAbsent(method.getReference(), ignore -> new Node(method));
}
}
@@ -108,9 +108,9 @@
class InvokeExtractor extends UseRegistry {
private final Node currentMethod;
- private final Predicate<DexEncodedMethod> targetTester;
+ private final Predicate<ProgramMethod> targetTester;
- InvokeExtractor(Node currentMethod, Predicate<DexEncodedMethod> targetTester) {
+ InvokeExtractor(Node currentMethod, Predicate<ProgramMethod> targetTester) {
super(appView.dexItemFactory());
this.currentMethod = currentMethod;
this.targetTester = targetTester;
@@ -119,7 +119,7 @@
private void addClassInitializerTarget(DexProgramClass clazz) {
assert clazz != null;
if (clazz.hasClassInitializer()) {
- addCallEdge(clazz.getClassInitializer(), false);
+ addCallEdge(clazz.getProgramClassInitializer(), false);
}
}
@@ -131,36 +131,42 @@
}
}
- private void addCallEdge(DexEncodedMethod callee, boolean likelySpuriousCallEdge) {
+ private void addCallEdge(ProgramMethod callee, boolean likelySpuriousCallEdge) {
if (!targetTester.test(callee)) {
return;
}
- if (callee.accessFlags.isAbstract()) {
+ if (callee.getDefinition().isAbstract()) {
// Not a valid target.
return;
}
- if (appView.appInfo().isPinned(callee.method)) {
+ if (callee.getDefinition().isNative()) {
+ // We don't care about calls to native methods.
+ return;
+ }
+ if (appView.appInfo().isPinned(callee.getReference())) {
// Since the callee is kept, we cannot inline it into the caller, and we also cannot collect
// any optimization info for the method. Therefore, we drop the call edge to reduce the
// total number of call graph edges, which should lead to fewer call graph cycles.
return;
}
- assert callee.isProgramMethod(appView);
getOrCreateNode(callee).addCallerConcurrently(currentMethod, likelySpuriousCallEdge);
}
private void addFieldReadEdge(DexEncodedMethod writer) {
- assert !writer.accessFlags.isAbstract();
+ addFieldReadEdge(writer.asProgramMethod(appView));
+ }
+
+ private void addFieldReadEdge(ProgramMethod writer) {
+ assert !writer.getDefinition().isAbstract();
if (!targetTester.test(writer)) {
return;
}
- assert writer.isProgramMethod(appView);
getOrCreateNode(writer).addReaderConcurrently(currentMethod);
}
private void processInvoke(Invoke.Type originalType, DexMethod originalMethod) {
- DexEncodedMethod source = currentMethod.method;
- DexMethod context = source.method;
+ ProgramMethod source = currentMethod.getProgramMethod();
+ DexMethod context = source.getReference();
GraphLenseLookupResult result =
appView.graphLense().lookupMethod(originalMethod, context, originalType);
DexMethod method = result.getMethod();
@@ -173,19 +179,16 @@
processInvokeWithDynamicDispatch(type, target, context.holder);
}
} else {
- DexEncodedMethod singleTarget =
- appView.appInfo().lookupSingleTarget(type, method, context.holder, appView);
+ ProgramMethod singleTarget =
+ appView.appInfo().lookupSingleProgramTarget(type, method, context.holder, appView);
if (singleTarget != null) {
- assert !source.accessFlags.isBridge() || singleTarget != currentMethod.method;
- DexProgramClass clazz =
- asProgramClassOrNull(appView.definitionFor(singleTarget.holder()));
- if (clazz != null) {
- // For static invokes, the class could be initialized.
- if (type == Invoke.Type.STATIC) {
- addClassInitializerTarget(clazz);
- }
- addCallEdge(singleTarget, false);
+ assert !source.getDefinition().isBridge()
+ || singleTarget.getDefinition() != source.getDefinition();
+ // For static invokes, the class could be initialized.
+ if (type == Invoke.Type.STATIC) {
+ addClassInitializerTarget(singleTarget.getHolder());
}
+ addCallEdge(singleTarget, false);
}
}
}
@@ -207,8 +210,8 @@
}
boolean isInterface = type == Invoke.Type.INTERFACE;
- Set<DexEncodedMethod> possibleTargets =
- possibleTargetsCache.computeIfAbsent(
+ ProgramMethodSet possibleProgramTargets =
+ possibleProgramTargetsCache.computeIfAbsent(
target,
method -> {
ResolutionResult resolution =
@@ -218,27 +221,34 @@
resolution.lookupVirtualDispatchTargets(
appView.definitionForProgramType(context), appView.appInfo());
if (lookupResult.isLookupResultSuccess()) {
- Set<DexEncodedMethod> targets = new HashSet<>();
+ ProgramMethodSet targets = ProgramMethodSet.create();
lookupResult
.asLookupResultSuccess()
.forEach(
- methodTarget -> targets.add(methodTarget.getDefinition()),
- lambdaTarget ->
- // The call target will ultimately be the implementation method.
- targets.add(
- lambdaTarget.getImplementationMethod().getDefinition()));
+ methodTarget -> {
+ if (methodTarget.isProgramMethod()) {
+ targets.add(methodTarget.asProgramMethod());
+ }
+ },
+ lambdaTarget -> {
+ // The call target will ultimately be the implementation method.
+ DexClassAndMethod implementationMethod =
+ lambdaTarget.getImplementationMethod();
+ if (implementationMethod.isProgramMethod()) {
+ targets.add(implementationMethod.asProgramMethod());
+ }
+ });
return targets;
}
}
return null;
});
- if (possibleTargets != null) {
+ if (possibleProgramTargets != null) {
boolean likelySpuriousCallEdge =
- possibleTargets.size() >= appView.options().callGraphLikelySpuriousCallEdgeThreshold;
- for (DexEncodedMethod possibleTarget : possibleTargets) {
- if (possibleTarget.isProgramMethod(appView)) {
- addCallEdge(possibleTarget, likelySpuriousCallEdge);
- }
+ possibleProgramTargets.size()
+ >= appView.options().callGraphLikelySpuriousCallEdgeThreshold;
+ for (ProgramMethod possibleTarget : possibleProgramTargets) {
+ addCallEdge(possibleTarget, likelySpuriousCallEdge);
}
}
}
@@ -401,19 +411,19 @@
static class CycleEliminationResult {
- private Map<DexEncodedMethod, Set<DexEncodedMethod>> removedCallEdges;
+ private Map<DexEncodedMethod, ProgramMethodSet> removedCallEdges;
- CycleEliminationResult(Map<DexEncodedMethod, Set<DexEncodedMethod>> removedCallEdges) {
+ CycleEliminationResult(Map<DexEncodedMethod, ProgramMethodSet> removedCallEdges) {
this.removedCallEdges = removedCallEdges;
}
- void forEachRemovedCaller(DexEncodedMethod callee, Consumer<DexEncodedMethod> fn) {
- removedCallEdges.getOrDefault(callee, ImmutableSet.of()).forEach(fn);
+ void forEachRemovedCaller(ProgramMethod callee, Consumer<ProgramMethod> fn) {
+ removedCallEdges.getOrDefault(callee.getDefinition(), ProgramMethodSet.empty()).forEach(fn);
}
int numberOfRemovedCallEdges() {
int numberOfRemovedCallEdges = 0;
- for (Set<DexEncodedMethod> nodes : removedCallEdges.values()) {
+ for (ProgramMethodSet nodes : removedCallEdges.values()) {
numberOfRemovedCallEdges += nodes.size();
}
return numberOfRemovedCallEdges;
@@ -445,7 +455,7 @@
private Map<Node, Set<Node>> writersToBeRemoved = new IdentityHashMap<>();
// Mapping from callee to the set of callers that were removed from the callee.
- private Map<DexEncodedMethod, Set<DexEncodedMethod>> removedCallEdges = new IdentityHashMap<>();
+ private Map<DexEncodedMethod, ProgramMethodSet> removedCallEdges = new IdentityHashMap<>();
// Set of nodes from which cycle elimination must be rerun to ensure that all cycles will be
// removed.
@@ -747,13 +757,13 @@
// All call edges where the callee is a method that should be force inlined must be kept,
// to guarantee that the IR converter will process the callee before the caller.
assert calleeOrWriter.hasCaller(callerOrReader);
- return !calleeOrWriter.method.getOptimizationInfo().forceInline();
+ return !calleeOrWriter.getMethod().getOptimizationInfo().forceInline();
}
private void recordCallEdgeRemoval(Node caller, Node callee) {
removedCallEdges
- .computeIfAbsent(callee.method, ignore -> SetUtils.newIdentityHashSet(2))
- .add(caller.method);
+ .computeIfAbsent(callee.getMethod(), ignore -> ProgramMethodSet.create(2))
+ .add(caller.getProgramMethod());
}
private void recoverStack(LinkedList<Node> extractedCycle) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
index 937b0ca..993315b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Sets;
@@ -15,13 +15,15 @@
/**
* Check if the <code>method</code> is guaranteed to only have a single call site.
- * <p>
- * For pinned methods (methods kept through Proguard keep rules) this will always answer
- * <code>false</code>.
+ *
+ * <p>For pinned methods (methods kept through Proguard keep rules) this will always answer <code>
+ * false</code>.
+ *
+ * @param method
*/
- public abstract boolean hasSingleCallSite(DexMethod method);
+ public abstract boolean hasSingleCallSite(ProgramMethod method);
- public abstract boolean hasDoubleCallSite(DexMethod method);
+ public abstract boolean hasDoubleCallSite(ProgramMethod method);
public static CallSiteInformation empty() {
return EmptyCallSiteInformation.EMPTY_INFO;
@@ -32,12 +34,12 @@
private static final EmptyCallSiteInformation EMPTY_INFO = new EmptyCallSiteInformation();
@Override
- public boolean hasSingleCallSite(DexMethod method) {
+ public boolean hasSingleCallSite(ProgramMethod method) {
return false;
}
@Override
- public boolean hasDoubleCallSite(DexMethod method) {
+ public boolean hasDoubleCallSite(ProgramMethod method) {
return false;
}
}
@@ -49,25 +51,25 @@
CallGraphBasedCallSiteInformation(AppView<AppInfoWithLiveness> appView, CallGraph graph) {
for (Node node : graph.nodes) {
- DexEncodedMethod encodedMethod = node.method;
- DexMethod method = encodedMethod.method;
+ ProgramMethod method = node.getProgramMethod();
+ DexMethod reference = method.getReference();
// For non-pinned methods and methods that override library methods we do not know the exact
// number of call sites.
- if (appView.appInfo().isPinned(method)) {
+ if (appView.appInfo().isPinned(reference)) {
continue;
}
if (appView.options().disableInliningOfLibraryMethodOverrides
- && encodedMethod.isLibraryMethodOverride().isTrue()) {
+ && method.getDefinition().isLibraryMethodOverride().isTrue()) {
continue;
}
int numberOfCallSites = node.getNumberOfCallSites();
if (numberOfCallSites == 1) {
- singleCallSite.add(method);
+ singleCallSite.add(reference);
} else if (numberOfCallSites == 2) {
- doubleCallSite.add(method);
+ doubleCallSite.add(reference);
}
}
}
@@ -79,8 +81,8 @@
* library method this always returns false.
*/
@Override
- public boolean hasSingleCallSite(DexMethod method) {
- return singleCallSite.contains(method);
+ public boolean hasSingleCallSite(ProgramMethod method) {
+ return singleCallSite.contains(method.getReference());
}
/**
@@ -90,8 +92,8 @@
* library method this always returns false.
*/
@Override
- public boolean hasDoubleCallSite(DexMethod method) {
- return doubleCallSite.contains(method);
+ public boolean hasDoubleCallSite(ProgramMethod method) {
+ return doubleCallSite.contains(method.getReference());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index f13653a..d4c8040 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Monitor;
@@ -201,7 +202,7 @@
private CfState state;
private final List<CfCode.LocalVariableInfo> localVariables;
private final CfCode code;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
private final Origin origin;
private final AppView<?> appView;
@@ -219,7 +220,7 @@
public CfSourceCode(
CfCode code,
List<CfCode.LocalVariableInfo> localVariables,
- DexEncodedMethod method,
+ ProgramMethod method,
DexMethod originalMethod,
Position callerPosition,
Origin origin,
@@ -244,9 +245,13 @@
internalOutputMode = appView.options().getInternalOutputMode();
needsGeneratedMethodSynchronization =
- !method.isProcessed()
+ !getMethod().isProcessed()
&& internalOutputMode.isGeneratingDex()
- && method.accessFlags.isSynchronized();
+ && getMethod().isSynchronized();
+ }
+
+ private DexEncodedMethod getMethod() {
+ return method.getDefinition();
}
public Origin getOrigin() {
@@ -385,15 +390,15 @@
inPrelude = true;
state.buildPrelude(canonicalPositions.getPreamblePosition());
setLocalVariableLists();
- builder.buildArgumentsWithRewrittenPrototypeChanges(0, method, state::write);
+ builder.buildArgumentsWithRewrittenPrototypeChanges(0, getMethod(), state::write);
// Add debug information for all locals at the initial label.
Int2ReferenceMap<DebugLocalInfo> locals = getLocalVariables(0).locals;
if (!locals.isEmpty()) {
int firstLocalIndex = 0;
- if (!method.isStatic()) {
+ if (!getMethod().isStatic()) {
firstLocalIndex++;
}
- for (DexType value : method.method.proto.parameters.values) {
+ for (DexType value : getMethod().proto().parameters.values) {
firstLocalIndex++;
if (value.isLongType() || value.isDoubleType()) {
firstLocalIndex++;
@@ -412,10 +417,6 @@
inPrelude = false;
}
- private boolean isStatic() {
- return method.accessFlags.isStatic();
- }
-
private boolean isCurrentlyGeneratingMethodSynchronization() {
return currentlyGeneratingMethodSynchronization;
}
@@ -427,9 +428,9 @@
private void buildMethodEnterSynchronization(IRBuilder builder) {
assert needsGeneratedMethodSynchronization;
currentlyGeneratingMethodSynchronization = true;
- DexType type = method.holder();
+ DexType type = method.getHolderType();
int monitorRegister;
- if (isStatic()) {
+ if (getMethod().isStatic()) {
monitorRegister = state.push(type).register;
state.pop();
builder.addConstClass(monitorRegister, type);
@@ -633,7 +634,7 @@
return ((CfNew) instruction).getType();
}
if (type.isUninitializedThis()) {
- return method.holder();
+ return method.getHolderType();
}
assert type.isTop();
return null;
@@ -777,7 +778,7 @@
.filter(insn -> insn instanceof CfPosition)
.map(insn -> ((CfPosition) insn).getPosition())
.collect(Collectors.toList()),
- method.method);
+ method.getReference());
}
while (offset + 1 < code.getInstructions().size()) {
CfInstruction insn = code.getInstructions().get(offset);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index f19ab4d..cd9bcd5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -36,10 +36,10 @@
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
import com.android.tools.r8.graph.DexDebugEntry;
import com.android.tools.r8.graph.DexDebugInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.CanonicalPositions;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.Position;
@@ -54,7 +54,7 @@
public class DexSourceCode implements SourceCode {
private final DexCode code;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
// Mapping from instruction offset to instruction index in the DexCode instruction array.
private final Map<Integer, Integer> offsetToInstructionIndex = new HashMap<>();
@@ -75,7 +75,7 @@
private final DexMethod originalMethod;
public DexSourceCode(
- DexCode code, DexEncodedMethod method, DexMethod originalMethod, Position callerPosition) {
+ DexCode code, ProgramMethod method, DexMethod originalMethod, Position callerPosition) {
this.code = code;
this.method = method;
this.originalMethod = originalMethod;
@@ -139,7 +139,7 @@
}
builder.buildArgumentsWithRewrittenPrototypeChanges(
code.registerSize - code.incomingRegisterSize,
- method,
+ method.getDefinition(),
DexSourceCode::doNothingWriteConsumer);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 35250d1..0dd98e2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
@@ -33,6 +32,7 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
@@ -392,8 +392,8 @@
private int currentInstructionOffset = -1;
final private ValueNumberGenerator valueNumberGenerator;
- private final DexEncodedMethod method;
- private DexEncodedMethod context;
+ private final ProgramMethod method;
+ private ProgramMethod context;
public final AppView<?> appView;
private final Origin origin;
private final RewrittenPrototypeDescription prototypeChanges;
@@ -429,18 +429,18 @@
private final IRMetadata metadata = new IRMetadata();
public static IRBuilder create(
- DexEncodedMethod method, AppView<?> appView, SourceCode source, Origin origin) {
+ ProgramMethod method, AppView<?> appView, SourceCode source, Origin origin) {
return new IRBuilder(
method,
appView,
source,
origin,
- lookupPrototypeChanges(appView, method.method),
+ lookupPrototypeChanges(appView, method),
new ValueNumberGenerator());
}
public static IRBuilder createForInlining(
- DexEncodedMethod method,
+ ProgramMethod method,
AppView<?> appView,
SourceCode source,
Origin origin,
@@ -448,15 +448,15 @@
ValueNumberGenerator valueNumberGenerator) {
RewrittenPrototypeDescription protoChanges =
processor.shouldApplyCodeRewritings(method)
- ? lookupPrototypeChanges(appView, method.method)
+ ? lookupPrototypeChanges(appView, method)
: RewrittenPrototypeDescription.none();
return new IRBuilder(method, appView, source, origin, protoChanges, valueNumberGenerator);
}
private static RewrittenPrototypeDescription lookupPrototypeChanges(
- AppView<?> appView, DexMethod method) {
+ AppView<?> appView, ProgramMethod method) {
RewrittenPrototypeDescription prototypeChanges =
- appView.graphLense().lookupPrototypeChanges(method);
+ appView.graphLense().lookupPrototypeChanges(method.getReference());
if (Log.ENABLED && prototypeChanges.getArgumentInfoCollection().hasRemovedArguments()) {
Log.info(
IRBuilder.class,
@@ -469,7 +469,7 @@
}
private IRBuilder(
- DexEncodedMethod method,
+ ProgramMethod method,
AppView<?> appView,
SourceCode source,
Origin origin,
@@ -486,7 +486,7 @@
}
public DexEncodedMethod getMethod() {
- return method;
+ return method.getDefinition();
}
public RewrittenPrototypeDescription getPrototypeChanges() {
@@ -494,7 +494,7 @@
}
public boolean isDebugMode() {
- return appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive();
+ return appView.options().debug || getMethod().getOptimizationInfo().isReachabilitySensitive();
}
public Int2ReferenceSortedMap<BlockInfo> getCFG() {
@@ -586,7 +586,7 @@
* @param context Under what context this IRCode is built. Either the current method or caller.
* @return The list of basic blocks. First block is the main entry.
*/
- public IRCode build(DexEncodedMethod context) {
+ public IRCode build(ProgramMethod context) {
assert source != null;
source.setUp();
@@ -705,7 +705,7 @@
// types, those could be still less precise at one single call site, where specific arguments
// will be passed during (double) inlining. Instead of adding assumptions and removing invalid
// ones, it's better not to insert assumptions for inlinee in the beginning.
- CallSiteOptimizationInfo callSiteOptimizationInfo = method.getCallSiteOptimizationInfo();
+ CallSiteOptimizationInfo callSiteOptimizationInfo = getMethod().getCallSiteOptimizationInfo();
if (method == context && appView.callSiteOptimizationInfoPropagator() != null) {
appView.callSiteOptimizationInfoPropagator()
.applyCallSiteOptimizationInfo(ir, callSiteOptimizationInfo);
@@ -724,7 +724,7 @@
}
public void constrainType(Value value, ValueTypeConstraint constraint) {
- value.constrainType(constraint, method.method, origin, appView.options().reporter);
+ value.constrainType(constraint, method.getReference(), origin, appView.options().reporter);
}
private void addImpreciseInstruction(ImpreciseMemberTypeInstruction instruction) {
@@ -932,7 +932,8 @@
void addThisArgument(int register) {
boolean receiverCouldBeNull = context != null && context != method;
Nullability nullability = receiverCouldBeNull ? maybeNull() : definitelyNotNull();
- TypeElement receiverType = TypeElement.fromDexType(method.holder(), nullability, appView);
+ TypeElement receiverType =
+ TypeElement.fromDexType(method.getHolderType(), nullability, appView);
addThisArgument(register, receiverType);
}
@@ -1463,16 +1464,11 @@
// therefore we use an invoke-direct instead. We need to do this as the Android Runtime
// will not allow invoke-virtual of a private method.
DexMethod invocationMethod = (DexMethod) item;
- DexType holderType = method.holder();
- if (invocationMethod.holder == holderType) {
- DexClass holderClass = appView.definitionFor(holderType);
- assert holderClass != null && holderClass.isProgramClass();
- if (holderClass != null) {
- DexEncodedMethod directTarget = holderClass.lookupDirectMethod(invocationMethod);
- if (directTarget != null && !directTarget.isStatic()) {
- assert invocationMethod.holder == directTarget.holder();
- type = Type.DIRECT;
- }
+ if (invocationMethod.holder == method.getHolderType()) {
+ DexEncodedMethod directTarget = method.getHolder().lookupDirectMethod(invocationMethod);
+ if (directTarget != null && !directTarget.isStatic()) {
+ assert invocationMethod.holder == directTarget.holder();
+ type = Type.DIRECT;
}
}
}
@@ -1764,7 +1760,8 @@
}
public void addReturn(int value) {
- if (method.method.proto.returnType == appView.dexItemFactory().voidType) {
+ DexType returnType = method.getDefinition().returnType();
+ if (returnType.isVoidType()) {
assert prototypeChanges.hasBeenChangedToReturnVoid(appView);
addReturn();
} else {
@@ -1772,7 +1769,7 @@
prototypeChanges.hasRewrittenReturnInfo()
? ValueTypeConstraint.fromDexType(
prototypeChanges.getRewrittenReturnInfo().getOldType())
- : ValueTypeConstraint.fromDexType(method.method.proto.returnType);
+ : ValueTypeConstraint.fromDexType(returnType);
Value in = readRegister(value, returnTypeConstraint);
addReturn(new Return(in));
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 7b15fcc..31fd3c0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
@@ -16,7 +15,6 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -25,6 +23,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.TypeChecker;
import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
import com.android.tools.r8.ir.analysis.fieldaccess.FieldAccessAnalysis;
@@ -90,7 +89,6 @@
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
@@ -105,11 +103,11 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.base.Suppliers;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -589,33 +587,34 @@
private void convertMethods(DexProgramClass clazz) {
boolean isReachabilitySensitive = clazz.hasReachabilitySensitiveAnnotation(options.itemFactory);
// When converting all methods on a class always convert <clinit> first.
- for (DexEncodedMethod method : clazz.directMethods()) {
- if (method.isClassInitializer()) {
- method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
- convertMethod(method);
- break;
- }
+ DexEncodedMethod classInitializer = clazz.getClassInitializer();
+ if (classInitializer != null) {
+ classInitializer
+ .getMutableOptimizationInfo()
+ .setReachabilitySensitive(isReachabilitySensitive);
+ convertMethod(new ProgramMethod(clazz, classInitializer));
}
- clazz.forEachMethod(
+ clazz.forEachProgramMethodMatching(
+ definition -> !definition.isClassInitializer(),
method -> {
- if (!method.isClassInitializer()) {
- method.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
- convertMethod(method);
- }
+ DexEncodedMethod definition = method.getDefinition();
+ definition.getMutableOptimizationInfo().setReachabilitySensitive(isReachabilitySensitive);
+ convertMethod(method);
});
}
- private void convertMethod(DexEncodedMethod method) {
- if (method.getCode() != null) {
- boolean matchesMethodFilter = options.methodMatchesFilter(method);
+ private void convertMethod(ProgramMethod method) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (definition.getCode() != null) {
+ boolean matchesMethodFilter = options.methodMatchesFilter(definition);
if (matchesMethodFilter) {
if (appView.options().enableNeverMergePrefixes) {
for (DexString neverMergePrefix : neverMergePrefixes) {
// Synthetic classes will always be merged.
- if (method.holder().isD8R8SynthesizedClassType()) {
+ if (method.getHolderType().isD8R8SynthesizedClassType()) {
continue;
}
- if (method.holder().descriptor.startsWith(neverMergePrefix)) {
+ if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) {
seenNeverMergePrefix.getAndSet(true);
} else {
seenNotNeverMergePrefix.getAndSet(true);
@@ -639,17 +638,15 @@
}
}
if (options.isGeneratingClassFiles()
- || !(options.passthroughDexCode && method.getCode().isDexCode())) {
+ || !(options.passthroughDexCode && definition.getCode().isDexCode())) {
// We do not process in call graph order, so anything could be a leaf.
rewriteCode(
- method,
- simpleOptimizationFeedback,
- OneTimeMethodProcessor.getInstance(ImmutableList.of(method)));
+ method, simpleOptimizationFeedback, OneTimeMethodProcessor.getInstance(method));
} else {
- assert method.getCode().isDexCode();
+ assert definition.getCode().isDexCode();
}
if (!options.isGeneratingClassFiles()) {
- updateHighestSortingStrings(method);
+ updateHighestSortingStrings(definition);
}
}
}
@@ -815,7 +812,7 @@
outliner.applyOutliningCandidate(code);
printMethod(code, "IR after outlining (SSA)", null);
removeDeadCodeAndFinalizeIR(
- code.method(), code, OptimizationFeedbackIgnore.getInstance(), Timing.empty());
+ code.context(), code, OptimizationFeedbackIgnore.getInstance(), Timing.empty());
},
executorService);
feedback.updateVisibleOptimizationInfo();
@@ -863,11 +860,11 @@
return builder.build();
}
- private void waveStart(Collection<DexEncodedMethod> wave) {
+ private void waveStart(ProgramMethodSet wave) {
onWaveDoneActions = Collections.synchronizedList(new ArrayList<>());
}
- private void waveDone(Collection<DexEncodedMethod> wave) {
+ private void waveDone(ProgramMethodSet wave) {
delayedOptimizationFeedback.refineAppInfoWithLiveness(appView.appInfo().withLiveness());
delayedOptimizationFeedback.updateVisibleOptimizationInfo();
if (options.enableFieldAssignmentTracker) {
@@ -904,13 +901,12 @@
Consumer<IRCode> consumer, ExecutorService executorService)
throws ExecutionException {
assert !options.skipIR;
- Set<DexEncodedMethod> methods = outliner.getMethodsSelectedForOutlining();
ThreadUtils.processItems(
- methods,
+ outliner.buildMethodsSelectedForOutlining(),
method -> {
- IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.holder()));
+ IRCode code = method.buildIR(appView);
assert code != null;
- assert !method.getCode().isOutlineCode();
+ assert !method.getDefinition().getCode().isOutlineCode();
// Instead of repeating all the optimizations of rewriteCode(), only run the
// optimizations needed for outlining: rewriteMoveResult() to remove out-values on
// StringBuilder/StringBuffer method invocations, and removeDeadCode() to remove
@@ -924,15 +920,15 @@
}
private void processSynthesizedServiceLoaderMethods(
- DexClass synthesizedClass, ExecutorService executorService) throws ExecutionException {
+ DexProgramClass synthesizedClass, ExecutorService executorService) throws ExecutionException {
ThreadUtils.processItems(
- synthesizedClass.methods(),
+ synthesizedClass::forEachProgramMethod,
this::forEachSynthesizedServiceLoaderMethod,
executorService);
}
- private void forEachSynthesizedServiceLoaderMethod(DexEncodedMethod method) {
- IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.holder()));
+ private void forEachSynthesizedServiceLoaderMethod(ProgramMethod method) {
+ IRCode code = method.buildIR(appView);
assert code != null;
codeRewriter.rewriteMoveResult(code);
removeDeadCodeAndFinalizeIR(
@@ -1017,8 +1013,8 @@
public void optimizeSynthesizedClass(
DexProgramClass clazz, ExecutorService executorService)
throws ExecutionException {
- Set<DexEncodedMethod> methods = Sets.newIdentityHashSet();
- clazz.forEachMethod(methods::add);
+ ProgramMethodSet methods = ProgramMethodSet.create();
+ clazz.forEachProgramMethod(methods::add);
// Process the generated class, but don't apply any outlining.
processMethodsConcurrently(methods, executorService);
}
@@ -1026,15 +1022,15 @@
public void optimizeSynthesizedClasses(
Collection<DexProgramClass> classes, ExecutorService executorService)
throws ExecutionException {
- Set<DexEncodedMethod> methods = Sets.newIdentityHashSet();
+ ProgramMethodSet methods = ProgramMethodSet.create();
for (DexProgramClass clazz : classes) {
- clazz.forEachMethod(methods::add);
+ clazz.forEachProgramMethod(methods::add);
}
processMethodsConcurrently(methods, executorService);
}
- public void optimizeSynthesizedMethod(DexEncodedMethod method) {
- if (!method.isProcessed()) {
+ public void optimizeSynthesizedMethod(ProgramMethod method) {
+ if (!method.getDefinition().isProcessed()) {
// Process the generated method, but don't apply any outlining.
processMethod(
method,
@@ -1043,12 +1039,13 @@
}
}
- public void processMethodsConcurrently(
- Collection<DexEncodedMethod> methods, ExecutorService executorService)
+ public void processMethodsConcurrently(ProgramMethodSet methods, ExecutorService executorService)
throws ExecutionException {
- OneTimeMethodProcessor processor = OneTimeMethodProcessor.getInstance(methods);
- processor.forEachWave(
- method -> processMethod(method, delayedOptimizationFeedback, processor), executorService);
+ if (!methods.isEmpty()) {
+ OneTimeMethodProcessor processor = OneTimeMethodProcessor.getInstance(methods);
+ processor.forEachWave(
+ method -> processMethod(method, delayedOptimizationFeedback, processor), executorService);
+ }
}
private String logCode(InternalOptions options, DexEncodedMethod method) {
@@ -1067,14 +1064,15 @@
// TODO(b/140766440): Make this receive a list of CodeOptimizations to conduct.
public Timing processMethod(
- DexEncodedMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
- Code code = method.getCode();
- boolean matchesMethodFilter = options.methodMatchesFilter(method);
+ ProgramMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
+ DexEncodedMethod definition = method.getDefinition();
+ Code code = definition.getCode();
+ boolean matchesMethodFilter = options.methodMatchesFilter(definition);
if (code != null && matchesMethodFilter) {
return rewriteCode(method, feedback, methodProcessor);
} else {
// Mark abstract methods as processed as well.
- method.markProcessed(ConstraintWithTarget.NEVER);
+ definition.markProcessed(ConstraintWithTarget.NEVER);
}
return Timing.empty();
}
@@ -1088,35 +1086,33 @@
}
private Timing rewriteCode(
- DexEncodedMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
- Origin origin = appView.appInfo().originFor(method.holder());
+ ProgramMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
return ExceptionUtils.withOriginAttachmentHandler(
- origin,
- new MethodPosition(method.method),
- () -> rewriteCodeInternal(method, feedback, methodProcessor, origin));
+ method.getOrigin(),
+ new MethodPosition(method.getReference()),
+ () -> rewriteCodeInternal(method, feedback, methodProcessor));
}
private Timing rewriteCodeInternal(
- DexEncodedMethod method,
- OptimizationFeedback feedback,
- MethodProcessor methodProcessor,
- Origin origin) {
-
+ ProgramMethod method, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
if (options.verbose) {
options.reporter.info(
new StringDiagnostic("Processing: " + method.toSourceString()));
}
if (Log.ENABLED) {
- Log.debug(getClass(), "Original code for %s:\n%s",
- method.toSourceString(), logCode(options, method));
+ Log.debug(
+ getClass(),
+ "Original code for %s:\n%s",
+ method.toSourceString(),
+ logCode(options, method.getDefinition()));
}
if (options.skipIR) {
- feedback.markProcessed(method, ConstraintWithTarget.NEVER);
+ feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return Timing.empty();
}
- IRCode code = method.buildIR(appView, origin);
+ IRCode code = method.buildIR(appView);
if (code == null) {
- feedback.markProcessed(method, ConstraintWithTarget.NEVER);
+ feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return Timing.empty();
}
return optimize(code, feedback, methodProcessor);
@@ -1125,8 +1121,9 @@
// TODO(b/140766440): Convert all sub steps an implementer of CodeOptimization
private Timing optimize(
IRCode code, OptimizationFeedback feedback, MethodProcessor methodProcessor) {
- DexEncodedMethod method = code.method();
- DexProgramClass holder = asProgramClassOrNull(appView.definitionForHolder(method));
+ ProgramMethod context = code.context();
+ DexEncodedMethod method = context.getDefinition();
+ DexProgramClass holder = context.getHolder();
assert holder != null;
Timing timing = Timing.create(method.qualifiedName(), options);
@@ -1157,7 +1154,7 @@
if (appView.graphLense().hasCodeRewritings()) {
assert lensCodeRewriter != null;
timing.begin("Lens rewrite");
- lensCodeRewriter.rewrite(code, method);
+ lensCodeRewriter.rewrite(code, context);
timing.end();
}
@@ -1175,7 +1172,7 @@
if (lambdaMerger != null) {
timing.begin("Merge lambdas");
- lambdaMerger.rewriteCode(method, code, inliner, methodProcessor);
+ lambdaMerger.rewriteCode(code.context(), code, inliner, methodProcessor);
timing.end();
assert code.isConsistentSSA();
}
@@ -1211,7 +1208,7 @@
if (identifierNameStringMarker != null) {
timing.begin("Decouple identifier-name strings");
- identifierNameStringMarker.decoupleIdentifierNameStringsInMethod(method, code);
+ identifierNameStringMarker.decoupleIdentifierNameStringsInMethod(code);
timing.end();
assert code.isConsistentSSA();
}
@@ -1242,14 +1239,14 @@
previous = printMethod(code, "IR after generated extension registry shrinking (SSA)", previous);
- appView.withGeneratedMessageLiteShrinker(shrinker -> shrinker.run(method, code));
+ appView.withGeneratedMessageLiteShrinker(shrinker -> shrinker.run(code));
timing.end();
previous = printMethod(code, "IR after generated message lite shrinking (SSA)", previous);
if (!isDebugMode && options.enableInlining && inliner != null) {
timing.begin("Inlining");
- inliner.performInlining(method, code, feedback, methodProcessor);
+ inliner.performInlining(code.context(), code, feedback, methodProcessor);
timing.end();
assert code.verifyTypes(appView);
}
@@ -1428,7 +1425,7 @@
codeRewriter,
stringOptimizer,
enumValueOptimizer,
- method,
+ code.context(),
code,
feedback,
methodProcessor,
@@ -1436,8 +1433,7 @@
Suppliers.memoize(
() ->
inliner.createDefaultOracle(
- method,
- code,
+ code.context(),
methodProcessor,
options.classInliningInstructionLimit,
// Inlining instruction allowance is not needed for the class inliner since it
@@ -1452,7 +1448,7 @@
if (d8NestBasedAccessDesugaring != null) {
timing.begin("Desugar nest access");
- d8NestBasedAccessDesugaring.rewriteNestBasedAccesses(method, code, appView);
+ d8NestBasedAccessDesugaring.rewriteNestBasedAccesses(context, code, appView);
timing.end();
assert code.isConsistentSSA();
}
@@ -1491,7 +1487,7 @@
if (lambdaMerger != null) {
timing.begin("Analyze lambda merging");
- lambdaMerger.analyzeCode(method, code);
+ lambdaMerger.analyzeCode(code.context(), code);
timing.end();
assert code.isConsistentSSA();
}
@@ -1515,7 +1511,7 @@
// Remove string switches prior to canonicalization to ensure that the constants that are
// being introduced will be canonicalized if possible.
timing.begin("Remove string switch");
- stringSwitchRemover.run(method, code);
+ stringSwitchRemover.run(code);
timing.end();
}
@@ -1549,7 +1545,7 @@
if (classStaticizer != null) {
timing.begin("Identify staticizing candidates");
- classStaticizer.examineMethodCode(method, code);
+ classStaticizer.examineMethodCode(code);
timing.end();
}
@@ -1591,7 +1587,7 @@
printMethod(code, "Optimized IR (SSA)", previous);
timing.begin("Finalize IR");
- finalizeIR(method, code, feedback, timing);
+ finalizeIR(code, feedback, timing);
timing.end();
return timing;
}
@@ -1653,22 +1649,21 @@
}
public void removeDeadCodeAndFinalizeIR(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+ ProgramMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
if (stringSwitchRemover != null) {
- stringSwitchRemover.run(method, code);
+ stringSwitchRemover.run(code);
}
deadCodeRemover.run(code, timing);
- finalizeIR(method, code, feedback, timing);
+ finalizeIR(code, feedback, timing);
}
- public void finalizeIR(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+ public void finalizeIR(IRCode code, OptimizationFeedback feedback, Timing timing) {
code.traceBlocks();
if (options.isGeneratingClassFiles()) {
- finalizeToCf(method, code, feedback);
+ finalizeToCf(code, feedback);
} else {
assert options.isGeneratingDex();
- finalizeToDex(method, code, feedback, timing);
+ finalizeToDex(code, feedback, timing);
}
}
@@ -1682,16 +1677,17 @@
feedback.markProcessed(method, ConstraintWithTarget.ALWAYS);
}
- private void finalizeToCf(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+ private void finalizeToCf(IRCode code, OptimizationFeedback feedback) {
+ DexEncodedMethod method = code.method();
assert !method.getCode().isDexCode();
CfBuilder builder = new CfBuilder(appView, method, code);
CfCode result = builder.build(deadCodeRemover);
method.setCode(result, appView);
- markProcessed(method, code, feedback);
+ markProcessed(code, feedback);
}
- private void finalizeToDex(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+ private void finalizeToDex(IRCode code, OptimizationFeedback feedback, Timing timing) {
+ DexEncodedMethod method = code.method();
// Workaround massive dex2oat memory use for self-recursive methods.
CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(appView, code);
// Perform register allocation.
@@ -1706,28 +1702,31 @@
}
printMethod(code, "Final IR (non-SSA)", null);
timing.begin("Marking processed");
- markProcessed(method, code, feedback);
+ markProcessed(code, feedback);
timing.end();
}
- private void markProcessed(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+ private void markProcessed(IRCode code, OptimizationFeedback feedback) {
// After all the optimizations have take place, we compute whether method should be inlined.
+ ProgramMethod method = code.context();
ConstraintWithTarget state =
shouldComputeInliningConstraint(method)
? inliner.computeInliningConstraint(code, method)
: ConstraintWithTarget.NEVER;
- feedback.markProcessed(method, state);
+ feedback.markProcessed(method.getDefinition(), state);
}
- private boolean shouldComputeInliningConstraint(DexEncodedMethod method) {
+ private boolean shouldComputeInliningConstraint(ProgramMethod method) {
if (!options.enableInlining || inliner == null) {
return false;
}
- if (method.isClassInitializer() || method.getOptimizationInfo().isReachabilitySensitive()) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (definition.isClassInitializer()
+ || definition.getOptimizationInfo().isReachabilitySensitive()) {
return false;
}
if (appView.appInfo().hasLiveness()
- && appView.appInfo().withLiveness().isPinned(method.method)) {
+ && appView.appInfo().withLiveness().isPinned(method.getReference())) {
return false;
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index e6f5e43..e94d07e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -35,7 +35,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -49,6 +48,7 @@
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
@@ -121,7 +121,7 @@
}
/** Replace type appearances, invoke targets and field accesses with actual definitions. */
- public void rewrite(IRCode code, DexEncodedMethod method) {
+ public void rewrite(IRCode code, ProgramMethod method) {
Set<Phi> affectedPhis =
enumUnboxer != null ? enumUnboxer.rewriteCode(code) : Sets.newIdentityHashSet();
GraphLense graphLense = appView.graphLense();
@@ -214,10 +214,10 @@
continue;
}
if (invoke.isInvokeDirect()) {
- checkInvokeDirect(method.method, invoke.asInvokeDirect());
+ checkInvokeDirect(method.getReference(), invoke.asInvokeDirect());
}
GraphLenseLookupResult lenseLookup =
- graphLense.lookupMethod(invokedMethod, method.method, invoke.getType());
+ graphLense.lookupMethod(invokedMethod, method.getReference(), invoke.getType());
DexMethod actualTarget = lenseLookup.getMethod();
Invoke.Type actualInvokeType = lenseLookup.getType();
if (actualTarget != invokedMethod || invoke.getType() != actualInvokeType) {
@@ -334,7 +334,7 @@
DexField field = instanceGet.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupGetFieldForMethod(actualField, method.method);
+ graphLense.lookupGetFieldForMethod(actualField, method.getReference());
if (replacementMethod != null) {
Value newOutValue = makeOutValue(current, code);
iterator.replaceCurrentInstruction(
@@ -359,7 +359,7 @@
DexField field = instancePut.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupPutFieldForMethod(actualField, method.method);
+ graphLense.lookupPutFieldForMethod(actualField, method.getReference());
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, null, current.inValues()));
@@ -381,7 +381,7 @@
DexField field = staticGet.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupGetFieldForMethod(actualField, method.method);
+ graphLense.lookupGetFieldForMethod(actualField, method.getReference());
if (replacementMethod != null) {
Value newOutValue = makeOutValue(current, code);
iterator.replaceCurrentInstruction(
@@ -405,7 +405,7 @@
DexField field = staticPut.getField();
DexField actualField = graphLense.lookupField(field);
DexMethod replacementMethod =
- graphLense.lookupPutFieldForMethod(actualField, method.method);
+ graphLense.lookupPutFieldForMethod(actualField, method.getReference());
if (replacementMethod != null) {
iterator.replaceCurrentInstruction(
new InvokeStatic(replacementMethod, current.outValue(), current.inValues()));
@@ -582,7 +582,7 @@
return TypeElement.getNull();
}
- public DexCallSite rewriteCallSite(DexCallSite callSite, DexEncodedMethod context) {
+ public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
DexProto newMethodProto =
dexItemFactory.applyClassMappingToProto(
@@ -682,7 +682,7 @@
}
private List<DexValue> rewriteBootstrapArgs(
- List<DexValue> bootstrapArgs, DexEncodedMethod method, MethodHandleUse use) {
+ List<DexValue> bootstrapArgs, ProgramMethod method, MethodHandleUse use) {
List<DexValue> newBootstrapArgs = null;
boolean changed = false;
for (int i = 0; i < bootstrapArgs.size(); i++) {
@@ -719,19 +719,21 @@
}
private DexValueMethodHandle rewriteDexValueMethodHandle(
- DexValueMethodHandle methodHandle, DexEncodedMethod context, MethodHandleUse use) {
+ DexValueMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) {
DexMethodHandle oldHandle = methodHandle.value;
DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, context, use);
return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle;
}
private DexMethodHandle rewriteDexMethodHandle(
- DexMethodHandle methodHandle, DexEncodedMethod context, MethodHandleUse use) {
+ DexMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) {
if (methodHandle.isMethodHandle()) {
DexMethod invokedMethod = methodHandle.asMethod();
MethodHandleType oldType = methodHandle.type;
GraphLenseLookupResult lenseLookup =
- appView.graphLense().lookupMethod(invokedMethod, context.method, oldType.toInvokeType());
+ appView
+ .graphLense()
+ .lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
DexMethod rewrittenTarget = lenseLookup.getMethod();
DexMethod actualTarget;
MethodHandleType newType;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
index 0c2eb60..b7ee7e1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
public interface MethodProcessor {
@@ -15,7 +15,7 @@
Phase getPhase();
- boolean shouldApplyCodeRewritings(DexEncodedMethod method);
+ boolean shouldApplyCodeRewritings(ProgramMethod method);
default boolean isPrimary() {
return getPhase() == Phase.PRIMARY;
@@ -29,5 +29,5 @@
return CallSiteInformation.empty();
}
- boolean isProcessedConcurrently(DexEncodedMethod method);
+ boolean isProcessedConcurrently(ProgramMethod method);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OneTimeMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/OneTimeMethodProcessor.java
index 939395f..071bfcb 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OneTimeMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OneTimeMethodProcessor.java
@@ -3,10 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
-import java.util.Collection;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -16,9 +16,9 @@
*/
public class OneTimeMethodProcessor implements MethodProcessor {
- private Collection<DexEncodedMethod> wave;
+ private ProgramMethodSet wave;
- private OneTimeMethodProcessor(Collection<DexEncodedMethod> methodsToProcess) {
+ private OneTimeMethodProcessor(ProgramMethodSet methodsToProcess) {
this.wave = methodsToProcess;
}
@@ -26,12 +26,16 @@
return new OneTimeMethodProcessor(null);
}
- public static OneTimeMethodProcessor getInstance(Collection<DexEncodedMethod> methodsToProcess) {
+ public static OneTimeMethodProcessor getInstance(ProgramMethod methodToProcess) {
+ return new OneTimeMethodProcessor(ProgramMethodSet.create(methodToProcess));
+ }
+
+ public static OneTimeMethodProcessor getInstance(ProgramMethodSet methodsToProcess) {
return new OneTimeMethodProcessor(methodsToProcess);
}
@Override
- public boolean shouldApplyCodeRewritings(DexEncodedMethod method) {
+ public boolean shouldApplyCodeRewritings(ProgramMethod method) {
return true;
}
@@ -41,12 +45,12 @@
}
@Override
- public boolean isProcessedConcurrently(DexEncodedMethod method) {
+ public boolean isProcessedConcurrently(ProgramMethod method) {
return wave != null && wave.contains(method);
}
public <E extends Exception> void forEachWave(
- ThrowingConsumer<DexEncodedMethod, E> consumer, ExecutorService executorService)
+ ThrowingConsumer<ProgramMethod, E> consumer, ExecutorService executorService)
throws ExecutionException {
ThreadUtils.processItems(wave, consumer, executorService);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PartialCallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/PartialCallGraphBuilder.java
index bfaf62c..e094867 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PartialCallGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PartialCallGraphBuilder.java
@@ -4,17 +4,18 @@
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
-import java.util.Set;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
public class PartialCallGraphBuilder extends CallGraphBuilderBase {
- private final Set<DexEncodedMethod> seeds;
- PartialCallGraphBuilder(AppView<AppInfoWithLiveness> appView, Set<DexEncodedMethod> seeds) {
+ private final ProgramMethodSet seeds;
+
+ PartialCallGraphBuilder(AppView<AppInfoWithLiveness> appView, ProgramMethodSet seeds) {
super(appView);
assert seeds != null && !seeds.isEmpty();
this.seeds = seeds;
@@ -25,17 +26,14 @@
ThreadUtils.processItems(seeds, this::processMethod, executorService);
}
- private void processMethod(DexEncodedMethod method) {
- if (method.hasCode()) {
- method.registerCodeReferences(
- new InvokeExtractor(getOrCreateNode(method), seeds::contains));
- }
+ private void processMethod(ProgramMethod method) {
+ method.registerCodeReferences(new InvokeExtractor(getOrCreateNode(method), seeds::contains));
}
@Override
boolean verifyAllMethodsWithCodeExists() {
- for (DexEncodedMethod method : seeds) {
- assert !method.hasCode() || nodes.get(method.method) != null;
+ for (ProgramMethod method : seeds) {
+ assert method.getDefinition().hasCode() == (nodes.get(method.getReference()) != null);
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index 328365e..7c136f6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -6,36 +6,34 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.IROrdering;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.stream.Collectors;
public class PostMethodProcessor implements MethodProcessor {
private final AppView<AppInfoWithLiveness> appView;
private final Map<DexEncodedMethod, Collection<CodeOptimization>> methodsMap;
- private final Deque<Set<DexEncodedMethod>> waves;
- private Set<DexEncodedMethod> wave;
- private final Set<DexEncodedMethod> processed = Sets.newIdentityHashSet();
+ private final Deque<ProgramMethodSet> waves;
+ private ProgramMethodSet wave;
+ private final ProgramMethodSet processed = ProgramMethodSet.create();
private PostMethodProcessor(
AppView<AppInfoWithLiveness> appView,
@@ -52,7 +50,7 @@
}
@Override
- public boolean shouldApplyCodeRewritings(DexEncodedMethod method) {
+ public boolean shouldApplyCodeRewritings(ProgramMethod method) {
assert !wave.contains(method);
return !processed.contains(method);
}
@@ -60,30 +58,33 @@
public static class Builder {
private final Collection<CodeOptimization> defaultCodeOptimizations;
- private final Map<DexEncodedMethod, Collection<CodeOptimization>> methodsMap =
- Maps.newIdentityHashMap();
+ private final LongLivedProgramMethodSetBuilder methodsMap =
+ new LongLivedProgramMethodSetBuilder();
+ private final Map<DexEncodedMethod, Collection<CodeOptimization>> optimizationsMap =
+ new IdentityHashMap<>();
Builder(Collection<CodeOptimization> defaultCodeOptimizations) {
this.defaultCodeOptimizations = defaultCodeOptimizations;
}
private void put(
- Set<DexEncodedMethod> methodsToRevisit, Collection<CodeOptimization> codeOptimizations) {
+ ProgramMethodSet methodsToRevisit, Collection<CodeOptimization> codeOptimizations) {
if (codeOptimizations.isEmpty()) {
// Nothing to conduct.
return;
}
- for (DexEncodedMethod method : methodsToRevisit) {
- methodsMap
+ for (ProgramMethod method : methodsToRevisit) {
+ methodsMap.add(method);
+ optimizationsMap
.computeIfAbsent(
- method,
+ method.getDefinition(),
// Optimization order might matter, hence a collection that preserves orderings.
k -> new LinkedHashSet<>())
.addAll(codeOptimizations);
}
}
- public void put(Set<DexEncodedMethod> methodsToRevisit) {
+ public void put(ProgramMethodSet methodsToRevisit) {
put(methodsToRevisit, defaultCodeOptimizations);
}
@@ -100,45 +101,54 @@
// new signature. The compiler needs to update the set of methods that must be reprocessed
// according to the graph lens.
public void mapDexEncodedMethods(AppView<?> appView) {
- Map<DexEncodedMethod, Collection<CodeOptimization>> newMethodsMap = new IdentityHashMap<>();
- methodsMap.forEach(
- (dexEncodedMethod, optimizations) -> {
- newMethodsMap.put(
- appView.graphLense().mapDexEncodedMethod(dexEncodedMethod, appView), optimizations);
- });
- methodsMap.clear();
- methodsMap.putAll(newMethodsMap);
+ Map<DexEncodedMethod, Collection<CodeOptimization>> newOptimizationsMap =
+ new IdentityHashMap<>();
+ optimizationsMap.forEach(
+ (method, optimizations) ->
+ newOptimizationsMap.put(
+ appView.graphLense().mapDexEncodedMethod(method, appView), optimizations));
+ optimizationsMap.clear();
+ optimizationsMap.putAll(newOptimizationsMap);
}
PostMethodProcessor build(
AppView<AppInfoWithLiveness> appView, ExecutorService executorService, Timing timing)
throws ExecutionException {
if (!appView.appInfo().reprocess.isEmpty()) {
- put(
- appView.appInfo().reprocess.stream()
- .map(appView::definitionFor)
- .filter(Objects::nonNull)
- .collect(Collectors.toSet()));
+ ProgramMethodSet set = ProgramMethodSet.create();
+ appView
+ .appInfo()
+ .reprocess
+ .forEach(
+ reference -> {
+ DexEncodedMethod definition = appView.definitionFor(reference);
+ if (definition != null) {
+ DexProgramClass clazz =
+ appView.definitionForHolder(definition).asProgramClass();
+ set.createAndAdd(clazz, definition);
+ }
+ });
+ put(set);
}
- if (methodsMap.keySet().isEmpty()) {
+ if (methodsMap.isEmpty()) {
// Nothing to revisit.
return null;
}
CallGraph callGraph =
- new PartialCallGraphBuilder(appView, methodsMap.keySet())
+ new PartialCallGraphBuilder(appView, methodsMap.build(appView))
.build(executorService, timing);
- return new PostMethodProcessor(appView, methodsMap, callGraph);
+ return new PostMethodProcessor(appView, optimizationsMap, callGraph);
}
}
- private Deque<Set<DexEncodedMethod>> createWaves(AppView<?> appView, CallGraph callGraph) {
+ private Deque<ProgramMethodSet> createWaves(AppView<?> appView, CallGraph callGraph) {
IROrdering shuffle = appView.options().testing.irOrdering;
- Deque<Set<DexEncodedMethod>> waves = new ArrayDeque<>();
+ Deque<ProgramMethodSet> waves = new ArrayDeque<>();
int waveCount = 1;
while (!callGraph.isEmpty()) {
- Set<DexEncodedMethod> wave = callGraph.extractRoots();
- waves.addLast(shuffle.order(wave));
+ ProgramMethodSet wave = callGraph.extractRoots();
+ waves.addLast(wave);
if (Log.ENABLED && Log.isLoggingEnabledFor(PostMethodProcessor.class)) {
Log.info(getClass(), "Wave #%d: %d", waveCount++, wave.size());
}
@@ -148,7 +158,7 @@
}
@Override
- public boolean isProcessedConcurrently(DexEncodedMethod method) {
+ public boolean isProcessedConcurrently(ProgramMethod method) {
return wave != null && wave.contains(method);
}
@@ -160,7 +170,7 @@
ThreadUtils.processItems(
wave,
method -> {
- Collection<CodeOptimization> codeOptimizations = methodsMap.get(method);
+ Collection<CodeOptimization> codeOptimizations = methodsMap.get(method.getDefinition());
assert codeOptimizations != null && !codeOptimizations.isEmpty();
forEachMethod(method, codeOptimizations, feedback);
},
@@ -170,19 +180,18 @@
}
private void forEachMethod(
- DexEncodedMethod method,
+ ProgramMethod method,
Collection<CodeOptimization> codeOptimizations,
OptimizationFeedback feedback) {
// TODO(b/140766440): Make IRConverter#process receive a list of CodeOptimization to conduct.
// Then, we can share IRCode creation there.
- Origin origin = appView.appInfo().originFor(method.holder());
if (appView.options().skipIR) {
- feedback.markProcessed(method, ConstraintWithTarget.NEVER);
+ feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return;
}
- IRCode code = method.buildIR(appView, origin);
+ IRCode code = method.buildIR(appView);
if (code == null) {
- feedback.markProcessed(method, ConstraintWithTarget.NEVER);
+ feedback.markProcessed(method.getDefinition(), ConstraintWithTarget.NEVER);
return;
}
// TODO(b/140768815): Reprocessing may trigger more methods to revisit. Update waves on-the-fly.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java b/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java
index 5ab18b3..7f06207 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java
@@ -3,19 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.Collection;
-import java.util.Set;
/**
* An abstraction of optimizations that require post processing of methods.
*/
public interface PostOptimization {
- /**
- * @return a set of methods that need post processing.
- */
- Set<DexEncodedMethod> methodsToRevisit();
+ /** @return a set of methods that need post processing. */
+ ProgramMethodSet methodsToRevisit();
// TODO(b/127694949): different CodeOptimization for primary processor v.s. post processor?
// In that way, instead of internal state changes, such as COLLECT v.s. APPLY or REVISIT,
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
index 5b26255..2a138cb 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
@@ -5,19 +5,17 @@
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.IROrdering;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.ThrowingFunction;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayDeque;
-import java.util.Collection;
import java.util.Deque;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -32,13 +30,13 @@
interface WaveStartAction {
- void notifyWaveStart(Collection<DexEncodedMethod> wave);
+ void notifyWaveStart(ProgramMethodSet wave);
}
private final CallSiteInformation callSiteInformation;
private final PostMethodProcessor.Builder postMethodProcessorBuilder;
- private final Deque<Collection<DexEncodedMethod>> waves;
- private Collection<DexEncodedMethod> wave;
+ private final Deque<ProgramMethodSet> waves;
+ private ProgramMethodSet wave;
private PrimaryMethodProcessor(
AppView<AppInfoWithLiveness> appView,
@@ -65,9 +63,9 @@
}
@Override
- public boolean shouldApplyCodeRewritings(DexEncodedMethod method) {
+ public boolean shouldApplyCodeRewritings(ProgramMethod method) {
assert !wave.contains(method);
- return !method.isProcessed();
+ return !method.getDefinition().isProcessed();
}
@Override
@@ -75,23 +73,22 @@
return callSiteInformation;
}
- private Deque<Collection<DexEncodedMethod>> createWaves(
+ private Deque<ProgramMethodSet> createWaves(
AppView<?> appView, CallGraph callGraph, CallSiteInformation callSiteInformation) {
InternalOptions options = appView.options();
- IROrdering shuffle = options.testing.irOrdering;
- Deque<Collection<DexEncodedMethod>> waves = new ArrayDeque<>();
-
+ Deque<ProgramMethodSet> waves = new ArrayDeque<>();
Set<Node> nodes = callGraph.nodes;
- Set<DexEncodedMethod> reprocessing = Sets.newIdentityHashSet();
+ ProgramMethodSet reprocessing = ProgramMethodSet.create();
int waveCount = 1;
while (!nodes.isEmpty()) {
- Set<DexEncodedMethod> wave = callGraph.extractLeaves();
- for (DexEncodedMethod method : wave) {
- if (callSiteInformation.hasSingleCallSite(method.method)) {
- callGraph.cycleEliminationResult.forEachRemovedCaller(method, reprocessing::add);
- }
- }
- waves.addLast(shuffle.order(wave));
+ ProgramMethodSet wave = callGraph.extractLeaves();
+ wave.forEach(
+ method -> {
+ if (callSiteInformation.hasSingleCallSite(method)) {
+ callGraph.cycleEliminationResult.forEachRemovedCaller(method, reprocessing::add);
+ }
+ });
+ waves.addLast(wave);
if (Log.ENABLED && Log.isLoggingEnabledFor(PrimaryMethodProcessor.class)) {
Log.info(getClass(), "Wave #%d: %d", waveCount++, wave.size());
}
@@ -104,7 +101,7 @@
}
@Override
- public boolean isProcessedConcurrently(DexEncodedMethod method) {
+ public boolean isProcessedConcurrently(ProgramMethod method) {
return wave != null && wave.contains(method);
}
@@ -115,9 +112,9 @@
* processed at the same time is passed. This can be used to avoid races in concurrent processing.
*/
<E extends Exception> void forEachMethod(
- ThrowingFunction<DexEncodedMethod, Timing, E> consumer,
+ ThrowingFunction<ProgramMethod, Timing, E> consumer,
WaveStartAction waveStartAction,
- Consumer<Collection<DexEncodedMethod>> waveDone,
+ Consumer<ProgramMethodSet> waveDone,
Timing timing,
ExecutorService executorService)
throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
index ebce25c..52a7d0a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
@@ -60,7 +59,7 @@
this.throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
}
- void run(DexEncodedMethod method, IRCode code) {
+ void run(IRCode code) {
if (!code.metadata().mayHaveStringSwitch()) {
assert Streams.stream(code.instructions()).noneMatch(Instruction::isStringSwitch);
return;
@@ -98,8 +97,7 @@
}
if (identifierNameStringMarker != null) {
- identifierNameStringMarker.decoupleIdentifierNameStringsInBlocks(
- method, code, newBlocksWithStrings);
+ identifierNameStringMarker.decoupleIdentifierNameStringsInBlocks(code, newBlocksWithStrings);
}
assert code.isConsistentSSA();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 56c1ff5..47ee95f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -18,11 +18,13 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
@@ -172,7 +174,7 @@
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final DexItemFactory dexItemFactory;
private final InterfaceMethodRewriter rewriter;
- private final Consumer<DexEncodedMethod> newSynthesizedMethodConsumer;
+ private final Consumer<ProgramMethod> newSynthesizedMethodConsumer;
private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
private final boolean needsLibraryInfo;
@@ -186,13 +188,13 @@
private final Map<DexClass, MethodSignatures> interfaceInfo = new IdentityHashMap<>();
// Mapping from actual program classes to the synthesized forwarding methods to be created.
- private final Map<DexProgramClass, List<DexEncodedMethod>> newSyntheticMethods =
+ private final Map<DexProgramClass, ProgramMethodSet> newSyntheticMethods =
new IdentityHashMap<>();
ClassProcessor(
AppView<? extends AppInfoWithClassHierarchy> appView,
InterfaceMethodRewriter rewriter,
- Consumer<DexEncodedMethod> newSynthesizedMethodConsumer) {
+ Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
this.rewriter = rewriter;
@@ -219,13 +221,11 @@
}
final void addSyntheticMethods() {
- for (DexProgramClass clazz : newSyntheticMethods.keySet()) {
- List<DexEncodedMethod> newForwardingMethods = newSyntheticMethods.get(clazz);
- if (newForwardingMethods != null) {
- clazz.addVirtualMethods(newForwardingMethods);
- newForwardingMethods.forEach(newSynthesizedMethodConsumer);
- }
- }
+ newSyntheticMethods.forEach(
+ (clazz, newForwardingMethods) -> {
+ clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
+ newForwardingMethods.forEach(newSynthesizedMethodConsumer);
+ });
}
// Computes the set of method signatures that may need forwarding methods on derived classes.
@@ -352,8 +352,10 @@
// Construction of actual forwarding methods.
- private void addSyntheticMethod(DexProgramClass clazz, DexEncodedMethod newMethod) {
- newSyntheticMethods.computeIfAbsent(clazz, key -> new ArrayList<>()).add(newMethod);
+ private void addSyntheticMethod(DexProgramClass clazz, DexEncodedMethod method) {
+ newSyntheticMethods
+ .computeIfAbsent(clazz, key -> ProgramMethodSet.create())
+ .createAndAdd(clazz, method);
}
private void addICCEThrowingMethod(DexMethod method, DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
index b5c3f3e..4d5c7be 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
@@ -20,6 +21,7 @@
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
@@ -63,7 +65,7 @@
// List of methods that should be added to the next class.
List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation = new LinkedList<>();
List<DexEncodedMethod> covariantReturnTypeMethods = new LinkedList<>();
- for (DexClass clazz : builder.getProgramClasses()) {
+ for (DexProgramClass clazz : builder.getProgramClasses()) {
// Construct the methods that should be added to clazz.
buildCovariantReturnTypeMethodsForClass(
clazz, methodsWithCovariantReturnTypeAnnotation, covariantReturnTypeMethods);
@@ -106,7 +108,7 @@
// CovariantReturnTypes annotations in the given DexClass. Adds the newly constructed, synthetic
// methods to the list covariantReturnTypeMethods.
private void buildCovariantReturnTypeMethodsForClass(
- DexClass clazz,
+ DexProgramClass clazz,
List<DexEncodedMethod> methodsWithCovariantReturnTypeAnnotation,
List<DexEncodedMethod> covariantReturnTypeMethods) {
for (DexEncodedMethod method : clazz.virtualMethods()) {
@@ -130,7 +132,9 @@
// variantReturnTypes annotations on the given method. Adds the newly constructed, synthetic
// methods to the list covariantReturnTypeMethods.
private void buildCovariantReturnTypeMethodsForMethod(
- DexClass clazz, DexEncodedMethod method, List<DexEncodedMethod> covariantReturnTypeMethods) {
+ DexProgramClass clazz,
+ DexEncodedMethod method,
+ List<DexEncodedMethod> covariantReturnTypeMethods) {
assert methodHasCovariantReturnTypeAnnotation(method);
for (DexType covariantReturnType : getCovariantReturnTypes(clazz, method)) {
DexEncodedMethod covariantReturnTypeMethod =
@@ -145,7 +149,7 @@
//
// Note: any "synchronized" or "strictfp" modifier could be dropped safely.
private DexEncodedMethod buildCovariantReturnTypeMethod(
- DexClass clazz, DexEncodedMethod method, DexType covariantReturnType) {
+ DexProgramClass clazz, DexEncodedMethod method, DexType covariantReturnType) {
DexProto newProto =
factory.createProto(
covariantReturnType, method.method.proto.parameters, method.method.proto.shorty);
@@ -170,7 +174,8 @@
new SynthesizedCode(forwardSourceCodeBuilder::build),
true);
// Optimize to generate DexCode instead of SynthesizedCode.
- converter.optimizeSynthesizedMethod(newVirtualMethod);
+ ProgramMethod programMethod = new ProgramMethod(clazz, newVirtualMethod);
+ converter.optimizeSynthesizedMethod(programMethod);
return newVirtualMethod;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index 738f4aa..f691760 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -10,7 +10,9 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -21,6 +23,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -41,20 +44,17 @@
// Maps a nest host to a class met which has that nest host.
// The value is used because the nest host might be missing.
- private final Map<DexType, DexClass> metNestHosts = new ConcurrentHashMap<>();
+ private final Map<DexType, DexProgramClass> metNestHosts = new ConcurrentHashMap<>();
public D8NestBasedAccessDesugaring(AppView<?> appView) {
super(appView);
}
- public void rewriteNestBasedAccesses(
- DexEncodedMethod encodedMethod, IRCode code, AppView<?> appView) {
- DexClass currentClass = appView.definitionFor(encodedMethod.holder());
- assert currentClass != null;
- if (!currentClass.isInANest()) {
+ public void rewriteNestBasedAccesses(ProgramMethod method, IRCode code, AppView<?> appView) {
+ if (!method.getHolder().isInANest()) {
return;
}
- metNestHosts.put(currentClass.getNestHost(), currentClass);
+ metNestHosts.put(method.getHolder().getNestHost(), method.getHolder());
ListIterator<BasicBlock> blocks = code.listIterator();
while (blocks.hasNext()) {
@@ -67,8 +67,7 @@
DexMethod methodCalled = invokeMethod.getInvokedMethod();
DexEncodedMethod encodedMethodCalled =
methodCalled.holder.isClassType() ? appView.definitionFor(methodCalled) : null;
- if (encodedMethodCalled != null
- && invokeRequiresRewriting(encodedMethodCalled, currentClass)) {
+ if (encodedMethodCalled != null && invokeRequiresRewriting(encodedMethodCalled, method)) {
DexMethod bridge = ensureInvokeBridge(encodedMethodCalled);
if (encodedMethodCalled.isInstanceInitializer()) {
instructions.previous();
@@ -87,7 +86,7 @@
} else if (instruction.isFieldInstruction()) {
DexEncodedField encodedField =
appView.definitionFor(instruction.asFieldInstruction().getField());
- if (encodedField != null && fieldAccessRequiresRewriting(encodedField, currentClass)) {
+ if (encodedField != null && fieldAccessRequiresRewriting(encodedField, method)) {
if (instruction.isInstanceGet() || instruction.isStaticGet()) {
DexMethod bridge = ensureFieldAccessBridge(encodedField, true);
instructions.replaceCurrentInstruction(
@@ -106,7 +105,7 @@
private void processNestsConcurrently(ExecutorService executorService) throws ExecutionException {
List<Future<?>> futures = new ArrayList<>();
- for (DexClass clazz : metNestHosts.values()) {
+ for (DexProgramClass clazz : metNestHosts.values()) {
futures.add(asyncProcessNest(clazz, executorService));
}
ThreadUtils.awaitFutures(futures);
@@ -118,17 +117,15 @@
addDeferredBridges(putFieldBridges.values());
}
- private void addDeferredBridges(Collection<DexEncodedMethod> bridges) {
- for (DexEncodedMethod bridge : bridges) {
- DexClass holder = definitionFor(bridge.holder());
- assert holder != null && holder.isProgramClass();
- holder.asProgramClass().addMethod(bridge);
+ private void addDeferredBridges(Collection<ProgramMethod> bridges) {
+ for (ProgramMethod bridge : bridges) {
+ bridge.getHolder().addMethod(bridge.getDefinition());
}
}
private void optimizeDeferredBridgesConcurrently(
ExecutorService executorService, IRConverter converter) throws ExecutionException {
- Collection<DexEncodedMethod> methods = new ArrayList<>();
+ ProgramMethodSet methods = ProgramMethodSet.create();
methods.addAll(bridges.values());
methods.addAll(getFieldBridges.values());
methods.addAll(putFieldBridges.values());
@@ -147,7 +144,7 @@
// In D8, programClass are processed on the fly so they do not need to be processed again here.
@Override
protected boolean shouldProcessClassInNest(DexClass clazz, List<DexType> nest) {
- return clazz.isNotProgramClass();
+ return clazz.isClasspathClass();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
index b9913cc..ca7fdec 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryAPIConverter.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -29,14 +30,13 @@
import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.WorkList;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
@@ -72,7 +72,7 @@
private final Mode mode;
private final DesugaredLibraryWrapperSynthesizer wrapperSynthesizor;
private final Map<DexClass, Set<DexEncodedMethod>> callBackMethods = new IdentityHashMap<>();
- private final Map<DexClass, List<DexEncodedMethod>> pendingCallBackMethods =
+ private final Map<DexProgramClass, List<DexEncodedMethod>> pendingCallBackMethods =
new IdentityHashMap<>();
private final Set<DexMethod> trackedCallBackAPIs;
private final Set<DexMethod> trackedAPIs;
@@ -111,9 +111,9 @@
}
if (!canGenerateWrappersAndCallbacks()) {
- assert validateCallbackWasGeneratedInEnqueuer(code.method());
+ assert validateCallbackWasGeneratedInEnqueuer(code.context());
} else {
- registerCallbackIfRequired(code.method());
+ registerCallbackIfRequired(code.context());
}
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -136,14 +136,12 @@
}
}
- private boolean validateCallbackWasGeneratedInEnqueuer(DexEncodedMethod encodedMethod) {
- if (!shouldRegisterCallback(encodedMethod)) {
+ private boolean validateCallbackWasGeneratedInEnqueuer(ProgramMethod method) {
+ if (!shouldRegisterCallback(method)) {
return true;
}
- DexProgramClass holderClass = appView.definitionForProgramType(encodedMethod.holder());
- DexMethod installedCallback =
- methodWithVivifiedTypeInSignature(encodedMethod.method, holderClass.type, appView);
- assert holderClass.lookupMethod(installedCallback) != null;
+ DexMethod installedCallback = methodWithVivifiedTypeInSignature(method, appView);
+ assert method.getHolder().lookupMethod(installedCallback) != null;
return true;
}
@@ -159,15 +157,13 @@
return appView.rewritePrefix.hasRewrittenTypeInSignature(invokedMethod.proto, appView);
}
- public void registerCallbackIfRequired(DexEncodedMethod encodedMethod) {
- if (shouldRegisterCallback(encodedMethod)) {
- DexClass dexClass = appView.definitionFor(encodedMethod.holder());
- assert dexClass != null;
- registerCallback(dexClass, encodedMethod);
+ public void registerCallbackIfRequired(ProgramMethod method) {
+ if (shouldRegisterCallback(method)) {
+ registerCallback(method);
}
}
- private boolean shouldRegisterCallback(DexEncodedMethod encodedMethod) {
+ private boolean shouldRegisterCallback(ProgramMethod method) {
// Any override of a library method can be called by the library.
// We duplicate the method to have a vivified type version callable by the library and
// a type version callable by the program. We need to add the vivified version to the rootset
@@ -175,36 +171,32 @@
// library type), but the enqueuer cannot see that.
// To avoid too much computation we first look if the method would need to be rewritten if
// it would override a library method, then check if it overrides a library method.
- if (encodedMethod.isPrivateMethod()
- || encodedMethod.isStatic()
- || encodedMethod.isLibraryMethodOverride().isFalse()) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (definition.isPrivateMethod()
+ || definition.isStatic()
+ || definition.isLibraryMethodOverride().isFalse()) {
return false;
}
- DexMethod method = encodedMethod.method;
- if (method.holder.isArrayType()
- || !appView.rewritePrefix.hasRewrittenTypeInSignature(method.proto, appView)
+ if (!appView.rewritePrefix.hasRewrittenTypeInSignature(definition.proto(), appView)
|| appView
.options()
.desugaredLibraryConfiguration
.getEmulateLibraryInterface()
- .containsKey(method.holder)) {
+ .containsKey(method.getHolderType())) {
return false;
}
- DexClass dexClass = appView.definitionFor(method.holder);
- if (dexClass == null) {
- return false;
- }
- return overridesLibraryMethod(dexClass, method);
+ return overridesLibraryMethod(method);
}
- private boolean overridesLibraryMethod(DexClass theClass, DexMethod method) {
+ private boolean overridesLibraryMethod(ProgramMethod method) {
// We look up everywhere to see if there is a supertype/interface implementing the method...
+ DexProgramClass holder = method.getHolder();
WorkList<DexType> workList = WorkList.newIdentityWorkList();
- workList.addIfNotSeen(theClass.interfaces.values);
+ workList.addIfNotSeen(holder.interfaces.values);
boolean foundOverrideToRewrite = false;
// There is no methods with desugared types on Object.
- if (theClass.superType != factory.objectType) {
- workList.addIfNotSeen(theClass.superType);
+ if (holder.superType != factory.objectType) {
+ workList.addIfNotSeen(holder.superType);
}
while (workList.hasNext()) {
DexType current = workList.next();
@@ -219,7 +211,7 @@
if (!dexClass.isLibraryClass() && !appView.options().isDesugaredLibraryCompilation()) {
continue;
}
- DexEncodedMethod dexEncodedMethod = dexClass.lookupVirtualMethod(method);
+ DexEncodedMethod dexEncodedMethod = dexClass.lookupVirtualMethod(method.getReference());
if (dexEncodedMethod != null) {
// In this case, the object will be wrapped.
if (appView.rewritePrefix.hasRewrittenType(dexClass.type, appView)) {
@@ -231,34 +223,41 @@
return foundOverrideToRewrite;
}
- private synchronized void registerCallback(DexClass dexClass, DexEncodedMethod originalMethod) {
+ private synchronized void registerCallback(ProgramMethod method) {
// In R8 we should be in the enqueuer, therefore we can duplicate a default method and both
// methods will be desugared.
// In D8, this happens after interface method desugaring, we cannot introduce new default
// methods, but we do not need to since this is a library override (invokes will resolve) and
// all implementors have been enhanced with a forwarding method which will be duplicated.
if (!appView.enableWholeProgramOptimizations()) {
- if (dexClass.isInterface()
- && originalMethod.isDefaultMethod()
+ if (method.getHolder().isInterface()
+ && method.getDefinition().isDefaultMethod()
&& (!appView.options().canUseDefaultAndStaticInterfaceMethods()
|| appView.options().isDesugaredLibraryCompilation())) {
return;
}
}
if (trackedCallBackAPIs != null) {
- trackedCallBackAPIs.add(originalMethod.method);
+ trackedCallBackAPIs.add(method.getReference());
}
- addCallBackSignature(dexClass, originalMethod);
+ addCallBackSignature(method);
}
- private synchronized void addCallBackSignature(DexClass dexClass, DexEncodedMethod method) {
- assert dexClass.type == method.holder();
- if (callBackMethods.computeIfAbsent(dexClass, key -> new HashSet<>()).add(method)) {
- pendingCallBackMethods.computeIfAbsent(dexClass, key -> new ArrayList<>()).add(method);
+ private synchronized void addCallBackSignature(ProgramMethod method) {
+ DexProgramClass holder = method.getHolder();
+ DexEncodedMethod definition = method.getDefinition();
+ if (callBackMethods.computeIfAbsent(holder, key -> Sets.newIdentityHashSet()).add(definition)) {
+ pendingCallBackMethods.computeIfAbsent(holder, key -> new ArrayList<>()).add(definition);
}
}
public static DexMethod methodWithVivifiedTypeInSignature(
+ ProgramMethod method, AppView<?> appView) {
+ return methodWithVivifiedTypeInSignature(
+ method.getReference(), method.getHolderType(), appView);
+ }
+
+ public static DexMethod methodWithVivifiedTypeInSignature(
DexMethod originalMethod, DexType holder, AppView<?> appView) {
DexType[] newParameters = originalMethod.proto.parameters.values.clone();
int index = 0;
@@ -285,28 +284,32 @@
if (appView.enableWholeProgramOptimizations()) {
return;
}
- List<DexEncodedMethod> callbacks = generateCallbackMethods();
+ ProgramMethodSet callbacks = generateCallbackMethods();
irConverter.processMethodsConcurrently(callbacks, executorService);
wrapperSynthesizor.finalizeWrappersForD8(builder, irConverter, executorService);
}
- public List<DexEncodedMethod> generateCallbackMethods() {
+ public ProgramMethodSet generateCallbackMethods() {
if (appView.options().testing.trackDesugaredAPIConversions) {
generateTrackDesugaredAPIWarnings(trackedAPIs, "");
generateTrackDesugaredAPIWarnings(trackedCallBackAPIs, "callback ");
trackedAPIs.clear();
trackedCallBackAPIs.clear();
}
- List<DexEncodedMethod> result = new ArrayList<>();
+ ProgramMethodSet allCallbackMethods = ProgramMethodSet.create();
pendingCallBackMethods.forEach(
(clazz, callbacks) -> {
- List<DexEncodedMethod> generated =
- ListUtils.map(callbacks, callback -> generateCallbackMethod(callback, clazz));
- clazz.addVirtualMethods(generated);
- result.addAll(generated);
+ List<DexEncodedMethod> newVirtualMethods = new ArrayList<>();
+ callbacks.forEach(
+ callback -> {
+ ProgramMethod callbackMethod = generateCallbackMethod(callback, clazz);
+ newVirtualMethods.add(callbackMethod.getDefinition());
+ allCallbackMethods.add(callbackMethod);
+ });
+ clazz.addVirtualMethods(newVirtualMethods);
});
pendingCallBackMethods.clear();
- return result;
+ return allCallbackMethods;
}
public List<DexProgramClass> synthesizeWrappers(
@@ -319,21 +322,21 @@
return wrapperSynthesizor.synthesizeClasspathMock(classToMock, mockType, mockIsInterface);
}
- private DexEncodedMethod generateCallbackMethod(
- DexEncodedMethod originalMethod, DexClass dexClass) {
+ private ProgramMethod generateCallbackMethod(
+ DexEncodedMethod originalMethod, DexProgramClass clazz) {
DexMethod methodToInstall =
- methodWithVivifiedTypeInSignature(originalMethod.method, dexClass.type, appView);
+ methodWithVivifiedTypeInSignature(originalMethod.method, clazz.type, appView);
CfCode cfCode =
new APIConverterWrapperCfCodeProvider(
- appView, originalMethod.method, null, this, dexClass.isInterface())
+ appView, originalMethod.method, null, this, clazz.isInterface())
.generateCfCode();
- DexEncodedMethod newDexEncodedMethod =
+ DexEncodedMethod newMethod =
wrapperSynthesizor.newSynthesizedMethod(methodToInstall, originalMethod, cfCode);
- newDexEncodedMethod.setCode(cfCode, appView);
+ newMethod.setCode(cfCode, appView);
if (originalMethod.isLibraryMethodOverride().isTrue()) {
- newDexEncodedMethod.setLibraryMethodOverride(OptionalBool.TRUE);
+ newMethod.setLibraryMethodOverride(OptionalBool.TRUE);
}
- return newDexEncodedMethod;
+ return new ProgramMethod(clazz, newMethod);
}
private void generateTrackDesugaredAPIWarnings(Set<DexMethod> tracked, String inner) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index ecf9d2e..a640fb6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -274,28 +275,27 @@
map.putIfAbsent(emulatedDispatchMethod.holder, new ArrayList<>(1));
map.get(emulatedDispatchMethod.holder).add(emulatedDispatchMethod);
}
- List<DexEncodedMethod> addedMethods = new ArrayList<>();
+ ProgramMethodSet addedMethods = ProgramMethodSet.create();
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (clazz.superType == null) {
assert clazz.type == appView.dexItemFactory().objectType : clazz.type.toSourceString();
continue;
}
- DexClass dexClass = appView.definitionFor(clazz.superType);
+ DexClass superclass = appView.definitionFor(clazz.superType);
// Only performs computation if superclass is a library class, but not object to filter out
// the most common case.
- if (dexClass != null
- && dexClass.isLibraryClass()
- && dexClass.type != appView.dexItemFactory().objectType) {
- for (DexType dexType : map.keySet()) {
- if (inherit(dexClass.asLibraryClass(), dexType, emulatedDispatchMethods)) {
- addedMethods.addAll(addInterfacesAndForwardingMethods(clazz, map.get(dexType)));
- }
- }
+ if (superclass != null
+ && superclass.isLibraryClass()
+ && superclass.type != appView.dexItemFactory().objectType) {
+ map.forEach(
+ (type, methods) -> {
+ if (inherit(superclass.asLibraryClass(), type, emulatedDispatchMethods)) {
+ addInterfacesAndForwardingMethods(
+ clazz, methods, method -> addedMethods.createAndAdd(clazz, method));
+ }
+ });
}
}
- if (addedMethods.isEmpty()) {
- return;
- }
converter.processMethodsConcurrently(addedMethods, executorService);
}
@@ -318,14 +318,15 @@
return false;
}
- private List<DexEncodedMethod> addInterfacesAndForwardingMethods(
- DexProgramClass clazz, List<DexMethod> dexMethods) {
+ private void addInterfacesAndForwardingMethods(
+ DexProgramClass clazz,
+ List<DexMethod> methods,
+ Consumer<DexEncodedMethod> newForwardingMethodsConsumer) {
// DesugaredLibraryRetargeter emulate dispatch: insertion of a marker interface & forwarding
// methods.
// We cannot use the ClassProcessor since this applies up to 26, while the ClassProcessor
// applies up to 24.
- List<DexEncodedMethod> newForwardingMethods = new ArrayList<>();
- for (DexMethod dexMethod : dexMethods) {
+ for (DexMethod dexMethod : methods) {
DexType[] newInterfaces =
Arrays.copyOf(clazz.interfaces.values, clazz.interfaces.size() + 1);
newInterfaces[newInterfaces.length - 1] = dispatchInterfaceTypeFor(dexMethod);
@@ -334,10 +335,9 @@
if (dexEncodedMethod == null) {
DexEncodedMethod newMethod = createForwardingMethod(dexMethod, clazz);
clazz.addVirtualMethod(newMethod);
- newForwardingMethods.add(newMethod);
+ newForwardingMethodsConsumer.accept(newMethod);
}
}
- return newForwardingMethods;
}
private DexEncodedMethod createForwardingMethod(DexMethod target, DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 6467824..5d494bb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -46,6 +47,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -110,7 +112,7 @@
// All forwarding methods generated during desugaring. We don't synchronize access
// to this collection since it is only filled in ClassProcessor running synchronously.
- private final Set<DexEncodedMethod> synthesizedMethods = Sets.newIdentityHashSet();
+ private final ProgramMethodSet synthesizedMethods = ProgramMethodSet.create();
// Caches default interface method info for already processed interfaces.
private final Map<DexType, DefaultMethodsHelper.Collection> cache = new ConcurrentHashMap<>();
@@ -675,28 +677,30 @@
emulateLibraryClassFlags.setFinal();
emulateLibraryClassFlags.setSynthetic();
emulateLibraryClassFlags.setPublic();
- synthesizedMethods.addAll(emulationMethods);
- return new DexProgramClass(
- emulateLibraryClassType,
- null,
- new SynthesizedOrigin("interface desugaring (libs)", getClass()),
- emulateLibraryClassFlags,
- factory.objectType,
- DexTypeList.empty(),
- theInterface.sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- // All synthesized methods are static in this case.
- emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType,
- Collections.singletonList(theInterface));
+ DexProgramClass clazz =
+ new DexProgramClass(
+ emulateLibraryClassType,
+ null,
+ new SynthesizedOrigin("interface desugaring (libs)", getClass()),
+ emulateLibraryClassFlags,
+ factory.objectType,
+ DexTypeList.empty(),
+ theInterface.sourceFile,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ // All synthesized methods are static in this case.
+ emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
+ DexEncodedMethod.EMPTY_ARRAY,
+ factory.getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType,
+ Collections.singletonList(theInterface));
+ clazz.forEachProgramMethod(synthesizedMethods::add);
+ return clazz;
}
private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
@@ -1020,7 +1024,8 @@
}
}
for (Entry<DexLibraryClass, Set<DexProgramClass>> entry : requiredDispatchClasses.entrySet()) {
- synthesizedMethods.addAll(processor.process(entry.getKey(), entry.getValue()));
+ DexProgramClass dispatchClass = processor.process(entry.getKey(), entry.getValue());
+ dispatchClass.forEachProgramMethod(synthesizedMethods::add);
}
if (appView.enableWholeProgramOptimizations()) {
appView.setGraphLense(graphLensBuilder.build(appView.dexItemFactory(), appView.graphLense()));
@@ -1029,7 +1034,7 @@
}
private void processClasses(
- Builder<?> builder, Flavor flavour, Consumer<DexEncodedMethod> newSynthesizedMethodConsumer) {
+ Builder<?> builder, Flavor flavour, Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
ClassProcessor processor = new ClassProcessor(appView, this, newSynthesizedMethodConsumer);
// First we compute all desugaring *without* introducing forwarding methods.
for (DexProgramClass clazz : builder.getProgramClasses()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index ab5a9cd..f1a499a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -232,7 +232,7 @@
return c -> 7 * checksum;
}
- List<DexEncodedMethod> process(DexLibraryClass iface, Set<DexProgramClass> callers) {
+ DexProgramClass process(DexLibraryClass iface, Set<DexProgramClass> callers) {
assert iface.isInterface();
// The list of methods to be created in dispatch class.
@@ -305,7 +305,7 @@
DexProgramClass::checksumFromType,
callers);
syntheticClasses.put(iface.type, dispatchClass);
- return dispatchMethods;
+ return dispatchClass;
}
private boolean canMoveToCompanionClass(DexEncodedMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 88d21d4..05c9c66 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -512,7 +512,7 @@
final Invoke.Type invokeType;
private boolean hasEnsuredAccessibility;
- private DexEncodedMethod accessibilityBridge;
+ private ProgramMethod accessibilityBridge;
Target(DexMethod callTarget, Invoke.Type invokeType) {
assert callTarget != null;
@@ -522,10 +522,10 @@
}
// Ensure access of the referenced symbol(s).
- abstract DexEncodedMethod ensureAccessibility(boolean allowMethodModification);
+ abstract ProgramMethod ensureAccessibility(boolean allowMethodModification);
// Ensure access of the referenced symbol(s).
- public DexEncodedMethod ensureAccessibilityIfNeeded(boolean allowMethodModification) {
+ public ProgramMethod ensureAccessibilityIfNeeded(boolean allowMethodModification) {
if (!hasEnsuredAccessibility) {
accessibilityBridge = ensureAccessibility(allowMethodModification);
hasEnsuredAccessibility = true;
@@ -552,7 +552,7 @@
// The only case where we do Lambda desugaring with Cf to Cf is in L8.
// If the compilation is not coreLibraryCompilation, then the assertion
// implMethodHolder != null may fail, hence the assertion.
- assert options.isDesugaredLibraryCompilation() || options.enableCfInterfaceMethodDesugaring;
+ assert options.cfToCfDesugar;
DexMethod implMethod = descriptor.implHandle.asMethod();
DexClass implMethodHolder = definitionFor(implMethod.holder);
if (implMethodHolder == null) {
@@ -574,7 +574,7 @@
}
@Override
- DexEncodedMethod ensureAccessibility(boolean allowMethodModification) {
+ ProgramMethod ensureAccessibility(boolean allowMethodModification) {
return null;
}
}
@@ -590,7 +590,7 @@
}
@Override
- DexEncodedMethod ensureAccessibility(boolean allowMethodModification) {
+ ProgramMethod ensureAccessibility(boolean allowMethodModification) {
// We already found the static method to be called, just relax its accessibility.
target.getDefinition().accessFlags.unsetPrivate();
if (target.getHolder().isInterface()) {
@@ -609,11 +609,11 @@
}
@Override
- DexEncodedMethod ensureAccessibility(boolean allowMethodModification) {
+ ProgramMethod ensureAccessibility(boolean allowMethodModification) {
// For all instantiation points for which the compiler creates lambda$
// methods, it creates these methods in the same class/interface.
DexMethod implMethod = descriptor.implHandle.asMethod();
- DexClass implMethodHolder = definitionFor(implMethod.holder);
+ DexProgramClass implMethodHolder = definitionFor(implMethod.holder).asProgramClass();
DexEncodedMethod replacement =
implMethodHolder
@@ -649,7 +649,7 @@
assert replacement != null
: "Unexpected failure to find direct lambda target for: " + implMethod.qualifiedName();
- return replacement;
+ return new ProgramMethod(implMethodHolder, replacement);
}
}
@@ -661,7 +661,7 @@
}
@Override
- DexEncodedMethod ensureAccessibility(boolean allowMethodModification) {
+ ProgramMethod ensureAccessibility(boolean allowMethodModification) {
// When compiling with whole program optimization, check that we are not inplace modifying.
assert !(rewriter.getAppView().enableWholeProgramOptimizations() && allowMethodModification);
// For all instantiation points for which the compiler creates lambda$
@@ -673,34 +673,37 @@
: createSyntheticAccessor(implMethod, implMethodHolder);
}
- private DexEncodedMethod modifyLambdaImplementationMethod(
+ private ProgramMethod modifyLambdaImplementationMethod(
DexMethod implMethod, DexProgramClass implMethodHolder) {
- return implMethodHolder
- .getMethodCollection()
- .replaceDirectMethodWithVirtualMethod(
- implMethod,
- encodedMethod -> {
- assert encodedMethod.isDirectMethod();
- // We need to create a new method with the same code to be able to safely relax its
- // accessibility and make it virtual.
- MethodAccessFlags newAccessFlags = encodedMethod.accessFlags.copy();
- newAccessFlags.unsetPrivate();
- newAccessFlags.setPublic();
- DexEncodedMethod newMethod =
- new DexEncodedMethod(
- callTarget,
- newAccessFlags,
- encodedMethod.annotations(),
- encodedMethod.parameterAnnotationsList,
- encodedMethod.getCode(),
- true);
- newMethod.copyMetadata(encodedMethod);
- rewriter.originalMethodSignatures.put(callTarget, encodedMethod.method);
- return newMethod;
- });
+ DexEncodedMethod replacement =
+ implMethodHolder
+ .getMethodCollection()
+ .replaceDirectMethodWithVirtualMethod(
+ implMethod,
+ encodedMethod -> {
+ assert encodedMethod.isDirectMethod();
+ // We need to create a new method with the same code to be able to safely relax
+ // its
+ // accessibility and make it virtual.
+ MethodAccessFlags newAccessFlags = encodedMethod.accessFlags.copy();
+ newAccessFlags.unsetPrivate();
+ newAccessFlags.setPublic();
+ DexEncodedMethod newMethod =
+ new DexEncodedMethod(
+ callTarget,
+ newAccessFlags,
+ encodedMethod.annotations(),
+ encodedMethod.parameterAnnotationsList,
+ encodedMethod.getCode(),
+ true);
+ newMethod.copyMetadata(encodedMethod);
+ rewriter.originalMethodSignatures.put(callTarget, encodedMethod.method);
+ return newMethod;
+ });
+ return new ProgramMethod(implMethodHolder, replacement);
}
- private DexEncodedMethod createSyntheticAccessor(
+ private ProgramMethod createSyntheticAccessor(
DexMethod implMethod, DexProgramClass implMethodHolder) {
MethodAccessFlags accessorFlags =
MethodAccessFlags.fromSharedAccessFlags(
@@ -726,7 +729,7 @@
true);
implMethodHolder.addVirtualMethod(accessorEncodedMethod);
- return accessorEncodedMethod;
+ return new ProgramMethod(implMethodHolder, accessorEncodedMethod);
}
}
@@ -739,7 +742,7 @@
}
@Override
- DexEncodedMethod ensureAccessibility(boolean allowMethodModification) {
+ ProgramMethod ensureAccessibility(boolean allowMethodModification) {
// Create a static accessor with proper accessibility.
DexProgramClass accessorClass = programDefinitionFor(callTarget.holder);
assert accessorClass != null;
@@ -764,7 +767,7 @@
accessorClass.addDirectMethod(accessorEncodedMethod);
}
- return accessorEncodedMethod;
+ return new ProgramMethod(accessorClass, accessorEncodedMethod);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index 4236e52..6b41818 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -29,6 +30,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableSet;
@@ -115,11 +117,12 @@
private void synthesizeAccessibilityBridgesForLambdaClassesD8(
Collection<LambdaClass> lambdaClasses, IRConverter converter, ExecutorService executorService)
throws ExecutionException {
- Set<DexEncodedMethod> nonDexAccessibilityBridges = Sets.newIdentityHashSet();
+ ProgramMethodSet nonDexAccessibilityBridges = ProgramMethodSet.create();
for (LambdaClass lambdaClass : lambdaClasses) {
// This call may cause originalMethodSignatures to be updated.
- DexEncodedMethod accessibilityBridge = lambdaClass.target.ensureAccessibilityIfNeeded(true);
- if (accessibilityBridge != null && !accessibilityBridge.getCode().isDexCode()) {
+ ProgramMethod accessibilityBridge = lambdaClass.target.ensureAccessibilityIfNeeded(true);
+ if (accessibilityBridge != null
+ && !accessibilityBridge.getDefinition().getCode().isDexCode()) {
nonDexAccessibilityBridges.add(accessibilityBridge);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index f4e1f4a..7da225c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.ir.desugar;
+
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -21,6 +24,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.origin.SynthesizedOrigin;
@@ -55,9 +59,9 @@
protected final AppView<?> appView;
// Following maps are there to avoid creating the bridges multiple times
// and remember the bridges to add once the nests are processed.
- final Map<DexMethod, DexEncodedMethod> bridges = new ConcurrentHashMap<>();
- final Map<DexField, DexEncodedMethod> getFieldBridges = new ConcurrentHashMap<>();
- final Map<DexField, DexEncodedMethod> putFieldBridges = new ConcurrentHashMap<>();
+ final Map<DexMethod, ProgramMethod> bridges = new ConcurrentHashMap<>();
+ final Map<DexField, ProgramMethod> getFieldBridges = new ConcurrentHashMap<>();
+ final Map<DexField, ProgramMethod> putFieldBridges = new ConcurrentHashMap<>();
// Common single empty class for nest based private constructors
private final DexProgramClass nestConstructor;
private boolean nestConstructorUsed = false;
@@ -81,9 +85,9 @@
}
private DexEncodedMethod definitionFor(
- DexMethod method, DexMethod context, Invoke.Type invokeType) {
+ DexMethod method, DexClassAndMethod context, Invoke.Type invokeType) {
return appView.definitionFor(
- appView.graphLense().lookupMethod(method, context, invokeType).getMethod());
+ appView.graphLense().lookupMethod(method, context.getReference(), invokeType).getMethod());
}
private DexEncodedField definitionFor(DexField field) {
@@ -109,7 +113,7 @@
return new Pair<>(hostClass, classesInNest);
}
- Future<?> asyncProcessNest(DexClass clazz, ExecutorService executorService) {
+ Future<?> asyncProcessNest(DexProgramClass clazz, ExecutorService executorService) {
return executorService.submit(
() -> {
Pair<DexClass, List<DexType>> nest = extractNest(clazz);
@@ -133,11 +137,17 @@
} else {
reportDesugarDependencies(host, clazz);
if (shouldProcessClassInNest(clazz, nest)) {
- NestBasedAccessDesugaringUseRegistry registry =
- new NestBasedAccessDesugaringUseRegistry(clazz);
- for (DexEncodedMethod method : clazz.methods()) {
- registry.setContext(method.method);
- method.registerCodeReferences(registry);
+ for (DexEncodedMethod definition : clazz.methods()) {
+ if (clazz.isProgramClass()) {
+ ProgramMethod method = new ProgramMethod(clazz.asProgramClass(), definition);
+ method.registerCodeReferences(new NestBasedAccessDesugaringUseRegistry(method));
+ } else if (clazz.isClasspathClass()) {
+ ClasspathMethod method = new ClasspathMethod(clazz.asClasspathClass(), definition);
+ method.registerCodeReferencesForDesugaring(
+ new NestBasedAccessDesugaringUseRegistry(method));
+ } else {
+ assert false;
+ }
}
}
}
@@ -255,26 +265,26 @@
.createMethod(holderType, proto, computeFieldBridgeName(field, isGet));
}
- boolean invokeRequiresRewriting(DexEncodedMethod method, DexClass contextClass) {
+ boolean invokeRequiresRewriting(DexEncodedMethod method, DexClassAndMethod context) {
assert method != null;
// Rewrite only when targeting other nest members private fields.
- if (!method.accessFlags.isPrivate() || method.holder() == contextClass.type) {
+ if (!method.accessFlags.isPrivate() || method.holder() == context.getHolderType()) {
return false;
}
DexClass methodHolder = definitionFor(method.holder());
assert methodHolder != null; // from encodedMethod
- return methodHolder.getNestHost() == contextClass.getNestHost();
+ return methodHolder.getNestHost() == context.getHolder().getNestHost();
}
- boolean fieldAccessRequiresRewriting(DexEncodedField field, DexClass contextClass) {
+ boolean fieldAccessRequiresRewriting(DexEncodedField field, DexClassAndMethod context) {
assert field != null;
// Rewrite only when targeting other nest members private fields.
- if (!field.accessFlags.isPrivate() || field.holder() == contextClass.type) {
+ if (!field.accessFlags.isPrivate() || field.holder() == context.getHolderType()) {
return false;
}
DexClass fieldHolder = definitionFor(field.holder());
assert fieldHolder != null; // from encodedField
- return fieldHolder.getNestHost() == contextClass.getNestHost();
+ return fieldHolder.getNestHost() == context.getHolder().getNestHost();
}
private boolean holderRequiresBridge(DexClass holder) {
@@ -300,14 +310,16 @@
if (holderRequiresBridge(holder)) {
return bridgeMethod;
}
+ assert holder.isProgramClass();
// The map is used to avoid creating multiple times the bridge
// and remembers the bridges to add.
- Map<DexField, DexEncodedMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
+ Map<DexField, ProgramMethod> fieldMap = isGet ? getFieldBridges : putFieldBridges;
+ assert holder.isProgramClass();
fieldMap.computeIfAbsent(
field.field,
k ->
DexEncodedMethod.createFieldAccessorBridge(
- new DexFieldWithAccess(field, isGet), holder, bridgeMethod));
+ new DexFieldWithAccess(field, isGet), holder.asProgramClass(), bridgeMethod));
return bridgeMethod;
}
@@ -327,26 +339,23 @@
}
// The map is used to avoid creating multiple times the bridge
// and remembers the bridges to add.
+ assert holder.isProgramClass();
bridges.computeIfAbsent(
method.method,
k ->
method.isInstanceInitializer()
- ? method.toInitializerForwardingBridge(holder, bridgeMethod)
- : method.toStaticForwardingBridge(holder, computeMethodBridge(method)));
+ ? method.toInitializerForwardingBridge(holder.asProgramClass(), bridgeMethod)
+ : method.toStaticForwardingBridge(
+ holder.asProgramClass(), computeMethodBridge(method)));
return bridgeMethod;
}
protected class NestBasedAccessDesugaringUseRegistry extends UseRegistry {
- private final DexClass currentClass;
- private DexMethod context;
+ private final DexClassAndMethod context;
- NestBasedAccessDesugaringUseRegistry(DexClass currentClass) {
+ NestBasedAccessDesugaringUseRegistry(DexClassAndMethod context) {
super(appView.options().itemFactory);
- this.currentClass = currentClass;
- }
-
- public void setContext(DexMethod context) {
this.context = context;
}
@@ -357,7 +366,7 @@
return false;
}
DexEncodedMethod encodedMethod = definitionFor(method, context, invokeType);
- if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, currentClass)) {
+ if (encodedMethod != null && invokeRequiresRewriting(encodedMethod, context)) {
ensureInvokeBridge(encodedMethod);
return true;
}
@@ -366,7 +375,7 @@
private boolean registerFieldAccess(DexField field, boolean isGet) {
DexEncodedField encodedField = definitionFor(field);
- if (encodedField != null && fieldAccessRequiresRewriting(encodedField, currentClass)) {
+ if (encodedField != null && fieldAccessRequiresRewriting(encodedField, context)) {
ensureFieldAccessBridge(encodedField, isGet);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
index ca10fe6..b97888d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
@@ -7,10 +7,10 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -54,12 +54,11 @@
}
private <E> void addDeferredBridgesAndMapMethods(
- Map<E, DexEncodedMethod> bridges, BiConsumer<E, DexMethod> lensInserter) {
- for (Map.Entry<E, DexEncodedMethod> entry : bridges.entrySet()) {
- DexClass holder = definitionFor(entry.getValue().holder());
- assert holder != null && holder.isProgramClass();
- holder.asProgramClass().addMethod(entry.getValue());
- lensInserter.accept(entry.getKey(), entry.getValue().method);
+ Map<E, ProgramMethod> bridges, BiConsumer<E, DexMethod> lensInserter) {
+ for (Map.Entry<E, ProgramMethod> entry : bridges.entrySet()) {
+ ProgramMethod method = entry.getValue();
+ method.getHolder().addMethod(method.getDefinition());
+ lensInserter.accept(entry.getKey(), method.getReference());
}
bridges.clear();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
index 312ae5d..8d1124b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CallSiteOptimizationInfoPropagator.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -31,6 +32,7 @@
import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.LinkedList;
@@ -52,14 +54,14 @@
}
private final AppView<AppInfoWithLiveness> appView;
- private Set<DexEncodedMethod> revisitedMethods = null;
+ private ProgramMethodSet revisitedMethods = null;
private Mode mode = Mode.COLLECT;
public CallSiteOptimizationInfoPropagator(AppView<AppInfoWithLiveness> appView) {
assert appView.enableWholeProgramOptimizations();
this.appView = appView;
if (Log.isLoggingEnabledFor(CallSiteOptimizationInfoPropagator.class)) {
- revisitedMethods = Sets.newIdentityHashSet();
+ revisitedMethods = ProgramMethodSet.create();
}
}
@@ -67,9 +69,12 @@
assert Log.ENABLED;
if (revisitedMethods != null) {
Log.info(getClass(), "# of methods to revisit: %s", revisitedMethods.size());
- for (DexEncodedMethod m : revisitedMethods) {
- Log.info(getClass(), "%s: %s",
- m.toSourceString(), m.getCallSiteOptimizationInfo().toString());
+ for (ProgramMethod m : revisitedMethods) {
+ Log.info(
+ getClass(),
+ "%s: %s",
+ m.toSourceString(),
+ m.getDefinition().getCallSiteOptimizationInfo().toString());
}
}
}
@@ -245,7 +250,7 @@
if (abstractValue.isSingleValue()) {
assert appView.options().enablePropagationOfConstantsAtCallSites;
SingleValue singleValue = abstractValue.asSingleValue();
- if (singleValue.isMaterializableInContext(appView, code.method().holder())) {
+ if (singleValue.isMaterializableInContext(appView, code.context())) {
Instruction replacement =
singleValue.createMaterializingInstruction(appView, code, instr);
replacement.setPosition(instr.getPosition());
@@ -318,27 +323,29 @@
}
@Override
- public Set<DexEncodedMethod> methodsToRevisit() {
+ public ProgramMethodSet methodsToRevisit() {
mode = Mode.REVISIT;
- Set<DexEncodedMethod> targetsToRevisit = Sets.newIdentityHashSet();
+ ProgramMethodSet targetsToRevisit = ProgramMethodSet.create();
for (DexProgramClass clazz : appView.appInfo().classes()) {
- for (DexEncodedMethod method : clazz.methods()) {
- assert !method.isObsolete();
- if (method.shouldNotHaveCode()
- || !method.hasCode()
- || method.getCode().isEmptyVoidMethod()) {
- continue;
- }
- // TODO(b/139246447): Assert no BOTTOM left.
- CallSiteOptimizationInfo callSiteOptimizationInfo = method.getCallSiteOptimizationInfo();
- if (!callSiteOptimizationInfo.hasUsefulOptimizationInfo(appView, method)) {
- continue;
- }
- targetsToRevisit.add(method);
- if (appView.options().testing.callSiteOptimizationInfoInspector != null) {
- appView.options().testing.callSiteOptimizationInfoInspector.accept(method);
- }
- }
+ clazz.forEachProgramMethodMatching(
+ definition -> {
+ assert !definition.isObsolete();
+ if (definition.shouldNotHaveCode()
+ || !definition.hasCode()
+ || definition.getCode().isEmptyVoidMethod()) {
+ return false;
+ }
+ // TODO(b/139246447): Assert no BOTTOM left.
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ definition.getCallSiteOptimizationInfo();
+ return callSiteOptimizationInfo.hasUsefulOptimizationInfo(appView, definition);
+ },
+ method -> {
+ targetsToRevisit.add(method);
+ if (appView.options().testing.callSiteOptimizationInfoInspector != null) {
+ appView.options().testing.callSiteOptimizationInfoInspector.accept(method);
+ }
+ });
}
if (revisitedMethods != null) {
revisitedMethods.addAll(targetsToRevisit);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index db75756..e0066a7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.addMonitorEnterValue;
import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues;
@@ -16,6 +15,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
@@ -46,16 +46,13 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
-import java.util.function.Predicate;
public final class DefaultInliningOracle implements InliningOracle, InliningStrategy {
private final AppView<AppInfoWithLiveness> appView;
private final Inliner inliner;
- private final DexEncodedMethod method;
- private final IRCode code;
+ private final ProgramMethod method;
private final MethodProcessor methodProcessor;
- private final Predicate<DexEncodedMethod> isProcessedConcurrently;
private final InliningReasonStrategy reasonStrategy;
private final int inliningInstructionLimit;
private int instructionAllowance;
@@ -64,8 +61,7 @@
AppView<AppInfoWithLiveness> appView,
Inliner inliner,
InliningReasonStrategy inliningReasonStrategy,
- DexEncodedMethod method,
- IRCode code,
+ ProgramMethod method,
MethodProcessor methodProcessor,
int inliningInstructionLimit,
int inliningInstructionAllowance) {
@@ -73,9 +69,7 @@
this.inliner = inliner;
this.reasonStrategy = inliningReasonStrategy;
this.method = method;
- this.code = code;
this.methodProcessor = methodProcessor;
- this.isProcessedConcurrently = methodProcessor::isProcessedConcurrently;
this.inliningInstructionLimit = inliningInstructionLimit;
this.instructionAllowance = inliningInstructionAllowance;
}
@@ -87,40 +81,29 @@
private boolean isSingleTargetInvalid(
InvokeMethod invoke,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
if (singleTarget == null) {
throw new Unreachable(
"Unexpected attempt to inline invoke that does not have a single target");
}
- if (singleTarget.isClassInitializer()) {
+ if (singleTarget.getDefinition().isClassInitializer()) {
throw new Unreachable(
"Unexpected attempt to invoke a class initializer (`"
- + singleTarget.method.toSourceString()
+ + singleTarget.toSourceString()
+ "`)");
}
- if (!singleTarget.hasCode()) {
+ if (!singleTarget.getDefinition().hasCode()) {
whyAreYouNotInliningReporter.reportInlineeDoesNotHaveCode();
return true;
}
- DexClass clazz = appView.definitionFor(singleTarget.holder());
- if (!clazz.isProgramClass()) {
- if (clazz.isClasspathClass()) {
- whyAreYouNotInliningReporter.reportClasspathMethod();
- } else {
- assert clazz.isLibraryClass();
- whyAreYouNotInliningReporter.reportLibraryMethod();
- }
- return true;
- }
-
// Ignore the implicit receiver argument.
int numberOfArguments =
invoke.arguments().size() - BooleanUtils.intValue(invoke.isInvokeMethodWithReceiver());
- int arity = singleTarget.method.getArity();
+ int arity = singleTarget.getReference().getArity();
if (numberOfArguments != arity) {
whyAreYouNotInliningReporter.reportIncorrectArity(numberOfArguments, arity);
return true;
@@ -132,27 +115,28 @@
@Override
public boolean passesInliningConstraints(
InvokeMethod invoke,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
- if (singleTarget.getOptimizationInfo().neverInline()) {
+ DexEncodedMethod singleTargetMethod = singleTarget.getDefinition();
+ if (singleTargetMethod.getOptimizationInfo().neverInline()) {
whyAreYouNotInliningReporter.reportMarkedAsNeverInline();
return false;
}
// We don't inline into constructors when producing class files since this can mess up
// the stackmap, see b/136250031
- if (method.isInstanceInitializer()
+ if (method.getDefinition().isInstanceInitializer()
&& appView.options().isGeneratingClassFiles()
&& reason != Reason.FORCE) {
whyAreYouNotInliningReporter.reportNoInliningIntoConstructorsWhenGeneratingClassFiles();
return false;
}
- if (method == singleTarget) {
+ if (method.getDefinition() == singleTargetMethod) {
// Cannot handle recursive inlining at this point.
// Force inlined method should never be recursive.
- assert !singleTarget.getOptimizationInfo().forceInline();
+ assert !singleTargetMethod.getOptimizationInfo().forceInline();
whyAreYouNotInliningReporter.reportRecursiveMethod();
return false;
}
@@ -162,7 +146,7 @@
// or optimized code. Right now this happens for the class class staticizer, as it just
// processes all relevant methods in parallel with the full optimization pipeline enabled.
// TODO(sgjesse): Add this assert "assert !isProcessedConcurrently.test(candidate);"
- if (reason != Reason.FORCE && isProcessedConcurrently.test(singleTarget)) {
+ if (reason != Reason.FORCE && methodProcessor.isProcessedConcurrently(singleTarget)) {
whyAreYouNotInliningReporter.reportProcessedConcurrently();
return false;
}
@@ -170,10 +154,9 @@
InternalOptions options = appView.options();
if (options.featureSplitConfiguration != null
&& !options.featureSplitConfiguration.inSameFeatureOrBase(
- singleTarget.method, method.method)) {
+ singleTarget.getReference(), method.getReference())) {
// Still allow inlining if we inline from the base into a feature.
- DexClass clazz = asProgramClassOrNull(appView.definitionFor(singleTarget.method.holder));
- if (!options.featureSplitConfiguration.isInBase(clazz.asProgramClass())) {
+ if (!options.featureSplitConfiguration.isInBase(singleTarget.getHolder())) {
whyAreYouNotInliningReporter.reportInliningAcrossFeatureSplit();
return false;
}
@@ -216,16 +199,16 @@
// Don't inline code with references beyond root main dex classes into a root main dex class.
// If we do this it can increase the size of the main dex dependent classes.
if (reason != Reason.FORCE
- && inlineeRefersToClassesNotInMainDex(method.holder(), singleTarget)) {
+ && inlineeRefersToClassesNotInMainDex(method.getHolderType(), singleTarget)) {
whyAreYouNotInliningReporter.reportInlineeRefersToClassesNotInMainDex();
return false;
}
assert reason != Reason.FORCE
- || !inlineeRefersToClassesNotInMainDex(method.holder(), singleTarget);
+ || !inlineeRefersToClassesNotInMainDex(method.getHolderType(), singleTarget);
return true;
}
- private boolean inlineeRefersToClassesNotInMainDex(DexType holder, DexEncodedMethod target) {
+ private boolean inlineeRefersToClassesNotInMainDex(DexType holder, ProgramMethod target) {
if (inliner.mainDexClasses.isEmpty() || !inliner.mainDexClasses.getRoots().contains(holder)) {
return false;
}
@@ -234,9 +217,9 @@
}
private boolean satisfiesRequirementsForSimpleInlining(
- InvokeMethod invoke, DexEncodedMethod target) {
+ InvokeMethod invoke, ProgramMethod target) {
// If we are looking for a simple method, only inline if actually simple.
- Code code = target.getCode();
+ Code code = target.getDefinition().getCode();
int instructionLimit = computeInstructionLimit(invoke, target);
if (code.estimatedSizeForInliningAtMost(instructionLimit)) {
return true;
@@ -244,9 +227,9 @@
return false;
}
- private int computeInstructionLimit(InvokeMethod invoke, DexEncodedMethod candidate) {
+ private int computeInstructionLimit(InvokeMethod invoke, ProgramMethod candidate) {
int instructionLimit = inliningInstructionLimit;
- BitSet hints = candidate.getOptimizationInfo().getNonNullParamOrThrow();
+ BitSet hints = candidate.getDefinition().getOptimizationInfo().getNonNullParamOrThrow();
if (hints != null) {
List<Value> arguments = invoke.inValues();
if (invoke.isInvokeMethodWithReceiver()) {
@@ -266,15 +249,15 @@
}
@Override
- public DexEncodedMethod lookupSingleTarget(InvokeMethod invoke, DexType context) {
- return invoke.lookupSingleTarget(appView, context);
+ public ProgramMethod lookupSingleTarget(InvokeMethod invoke, ProgramMethod context) {
+ return invoke.lookupSingleProgramTarget(appView, context);
}
@Override
public InlineAction computeInlining(
InvokeMethod invoke,
- DexEncodedMethod singleTarget,
- DexEncodedMethod context,
+ ProgramMethod singleTarget,
+ ProgramMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
if (isSingleTargetInvalid(invoke, singleTarget, whyAreYouNotInliningReporter)) {
@@ -290,8 +273,9 @@
return null;
}
- if (!singleTarget.isInliningCandidate(
- method, reason, appView.appInfo(), whyAreYouNotInliningReporter)) {
+ if (!singleTarget
+ .getDefinition()
+ .isInliningCandidate(method, reason, appView.appInfo(), whyAreYouNotInliningReporter)) {
return null;
}
@@ -305,7 +289,7 @@
public InlineAction computeForInvokeWithReceiver(
InvokeMethodWithReceiver invoke,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
Value receiver = invoke.getReceiver();
@@ -322,7 +306,10 @@
// receiver. Therefore, if the receiver may be null and the candidate inlinee does not
// throw if the receiver is null before any other side effect, then we must synthesize a
// null check.
- if (!singleTarget.getOptimizationInfo().checksNullReceiverBeforeAnySideEffect()) {
+ if (!singleTarget
+ .getDefinition()
+ .getOptimizationInfo()
+ .checksNullReceiverBeforeAnySideEffect()) {
InternalOptions options = appView.options();
if (!options.enableInliningOfInvokesWithNullableReceivers) {
whyAreYouNotInliningReporter.reportReceiverMaybeNull();
@@ -336,12 +323,16 @@
public InlineAction computeForInvokeStatic(
InvokeStatic invoke,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Reason reason,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
InlineAction action = new InlineAction(singleTarget, invoke, reason);
- if (isTargetClassInitialized(invoke, method, singleTarget, classInitializationAnalysis)) {
+ if (isTargetClassInitialized(
+ invoke,
+ method.getDefinition(),
+ singleTarget.getDefinition(),
+ classInitializationAnalysis)) {
return action;
}
if (appView.canUseInitClass()
@@ -409,8 +400,8 @@
@Override
public void ensureMethodProcessed(
- DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback) {
- if (!target.isProcessed()) {
+ ProgramMethod target, IRCode inlinee, OptimizationFeedback feedback) {
+ if (!target.getDefinition().isProcessed()) {
if (Log.ENABLED) {
Log.verbose(getClass(), "Forcing extra inline on " + target.toSourceString());
}
@@ -450,10 +441,11 @@
// Allow inlining a constructor into a constructor of the same class, as the constructor code
// is expected to adhere to the VM specification.
- DexType callerMethodHolder = method.holder();
+ DexType callerMethodHolder = method.getHolderType();
DexType calleeMethodHolder = inlinee.method().holder();
// Calling a constructor on the same class from a constructor can always be inlined.
- if (method.isInstanceInitializer() && callerMethodHolder == calleeMethodHolder) {
+ if (method.getDefinition().isInstanceInitializer()
+ && callerMethodHolder == calleeMethodHolder) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index 26c28d7..a48dece 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -5,8 +5,8 @@
package com.android.tools.r8.ir.optimize;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
@@ -22,12 +22,12 @@
final class ForcedInliningOracle implements InliningOracle, InliningStrategy {
private final AppView<AppInfoWithLiveness> appView;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
private final Map<? extends InvokeMethod, Inliner.InliningInfo> invokesToInline;
ForcedInliningOracle(
AppView<AppInfoWithLiveness> appView,
- DexEncodedMethod method,
+ ProgramMethod method,
Map<? extends InvokeMethod, Inliner.InliningInfo> invokesToInline) {
this.appView = appView;
this.method = method;
@@ -42,26 +42,26 @@
@Override
public boolean passesInliningConstraints(
InvokeMethod invoke,
- DexEncodedMethod candidate,
+ ProgramMethod candidate,
Reason reason,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
return true;
}
@Override
- public DexEncodedMethod lookupSingleTarget(InvokeMethod invoke, DexType context) {
+ public ProgramMethod lookupSingleTarget(InvokeMethod invoke, ProgramMethod context) {
Inliner.InliningInfo info = invokesToInline.get(invoke);
if (info != null) {
return info.target;
}
- return invoke.lookupSingleTarget(appView, context);
+ return invoke.lookupSingleProgramTarget(appView, context);
}
@Override
public InlineAction computeInlining(
InvokeMethod invoke,
- DexEncodedMethod singleTarget,
- DexEncodedMethod context,
+ ProgramMethod singleTarget,
+ ProgramMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
return computeForInvoke(invoke, whyAreYouNotInliningReporter);
@@ -74,11 +74,11 @@
return null;
}
- assert method != info.target;
+ assert method.getDefinition() != info.target.getDefinition();
// Even though call to Inliner::performForcedInlining is supposed to be controlled by
// the caller, it's still suspicious if we want to force inline something that is marked
// with neverInline() flag.
- assert !info.target.getOptimizationInfo().neverInline();
+ assert !info.target.getDefinition().getOptimizationInfo().neverInline();
assert passesInliningConstraints(
invoke, info.target, Reason.FORCE, whyAreYouNotInliningReporter);
return new InlineAction(info.target, invoke, Reason.FORCE);
@@ -86,7 +86,7 @@
@Override
public void ensureMethodProcessed(
- DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback) {
+ ProgramMethod target, IRCode inlinee, OptimizationFeedback feedback) {
// Do nothing. If the method is not yet processed, we still should
// be able to build IR for inlining, though.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index fdb59ae..6db2341 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.proto.ProtoInliningReasonStrategy;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -62,6 +63,7 @@
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -69,7 +71,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
-import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
@@ -86,9 +88,10 @@
// State for inlining methods which are known to be called twice.
private boolean applyDoubleInlining = false;
- private final Set<DexEncodedMethod> doubleInlineCallers = Sets.newIdentityHashSet();
- private final Set<DexEncodedMethod> doubleInlineSelectedTargets = Sets.newIdentityHashSet();
- private final Map<DexEncodedMethod, DexEncodedMethod> doubleInlineeCandidates = new HashMap<>();
+ private final ProgramMethodSet doubleInlineCallers = ProgramMethodSet.create();
+ private final ProgramMethodSet doubleInlineSelectedTargets = ProgramMethodSet.create();
+ private final Map<DexEncodedMethod, ProgramMethod> doubleInlineeCandidates =
+ new IdentityHashMap<>();
private final AvailableApiExceptions availableApiExceptions;
@@ -113,25 +116,25 @@
}
boolean isBlacklisted(
- DexEncodedMethod encodedMethod, WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
- DexMethod method = encodedMethod.method;
- if (encodedMethod.getOptimizationInfo().forceInline()
- && appView.appInfo().neverInline.contains(method)) {
+ ProgramMethod method, WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
+ DexMethod reference = method.getReference();
+ if (method.getDefinition().getOptimizationInfo().forceInline()
+ && appView.appInfo().neverInline.contains(reference)) {
throw new Unreachable();
}
- if (appView.appInfo().isPinned(method)) {
+ if (appView.appInfo().isPinned(reference)) {
whyAreYouNotInliningReporter.reportPinned();
return true;
}
- if (blacklist.contains(appView.graphLense().getOriginalMethodSignature(method))
- || TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(method, appView)) {
+ if (blacklist.contains(appView.graphLense().getOriginalMethodSignature(reference))
+ || TwrCloseResourceRewriter.isSynthesizedCloseResourceMethod(reference, appView)) {
whyAreYouNotInliningReporter.reportBlacklisted();
return true;
}
- if (appView.appInfo().neverInline.contains(method)) {
+ if (appView.appInfo().neverInline.contains(reference)) {
whyAreYouNotInliningReporter.reportMarkedAsNeverInline();
return true;
}
@@ -153,7 +156,7 @@
return result;
}
- public ConstraintWithTarget computeInliningConstraint(IRCode code, DexEncodedMethod method) {
+ public ConstraintWithTarget computeInliningConstraint(IRCode code, ProgramMethod method) {
if (containsPotentialCatchHandlerVerificationError(code)) {
return ConstraintWithTarget.NEVER;
}
@@ -168,7 +171,7 @@
new InliningConstraints(appView, GraphLense.getIdentityLense());
for (Instruction instruction : code.instructions()) {
ConstraintWithTarget state =
- instructionAllowedForInlining(instruction, inliningConstraints, method.holder());
+ instructionAllowedForInlining(instruction, inliningConstraints, method.getHolderType());
if (state == ConstraintWithTarget.NEVER) {
result = state;
break;
@@ -179,8 +182,8 @@
return result;
}
- private boolean returnsIntAsBoolean(IRCode code, DexEncodedMethod method) {
- DexType returnType = method.method.proto.returnType;
+ private boolean returnsIntAsBoolean(IRCode code, ProgramMethod method) {
+ DexType returnType = method.getDefinition().returnType();
for (BasicBlock basicBlock : code.blocks) {
InstructionIterator instructionIterator = basicBlock.iterator();
while (instructionIterator.hasNext()) {
@@ -195,16 +198,17 @@
return false;
}
- boolean hasInliningAccess(DexEncodedMethod method, DexEncodedMethod target) {
- if (!isVisibleWithFlags(target.holder(), method.holder(), target.accessFlags)) {
+ boolean hasInliningAccess(ProgramMethod method, ProgramMethod target) {
+ if (!isVisibleWithFlags(
+ target.getHolderType(), method.getHolderType(), target.getDefinition().accessFlags)) {
return false;
}
// The class needs also to be visible for us to have access.
- DexClass targetClass = appView.definitionFor(target.holder());
- return isVisibleWithFlags(target.holder(), method.holder(), targetClass.accessFlags);
+ return isVisibleWithFlags(
+ target.getHolderType(), method.getHolderType(), target.getHolder().accessFlags);
}
- private boolean isVisibleWithFlags(DexType target, DexType context, AccessFlags flags) {
+ private boolean isVisibleWithFlags(DexType target, DexType context, AccessFlags<?> flags) {
if (flags.isPublic()) {
return true;
}
@@ -218,12 +222,12 @@
return target.isSamePackage(context);
}
- public synchronized boolean isDoubleInlineSelectedTarget(DexEncodedMethod method) {
+ public synchronized boolean isDoubleInlineSelectedTarget(ProgramMethod method) {
return doubleInlineSelectedTargets.contains(method);
}
synchronized boolean satisfiesRequirementsForDoubleInlining(
- DexEncodedMethod method, DexEncodedMethod target) {
+ ProgramMethod method, ProgramMethod target) {
if (applyDoubleInlining) {
// Don't perform the actual inlining if this was not selected.
return doubleInlineSelectedTargets.contains(target);
@@ -234,25 +238,25 @@
return false;
}
- synchronized void recordDoubleInliningCandidate(
- DexEncodedMethod method, DexEncodedMethod target) {
+ synchronized void recordDoubleInliningCandidate(ProgramMethod method, ProgramMethod target) {
if (applyDoubleInlining) {
return;
}
- if (doubleInlineeCandidates.containsKey(target)) {
+ if (doubleInlineeCandidates.containsKey(target.getDefinition())) {
// Both calls can be inlined.
- doubleInlineCallers.add(doubleInlineeCandidates.get(target));
+ ProgramMethod doubleInlineeCandidate = doubleInlineeCandidates.get(target.getDefinition());
+ doubleInlineCallers.add(doubleInlineeCandidate);
doubleInlineCallers.add(method);
doubleInlineSelectedTargets.add(target);
} else {
// First call can be inlined.
- doubleInlineeCandidates.put(target, method);
+ doubleInlineeCandidates.put(target.getDefinition(), method);
}
}
@Override
- public Set<DexEncodedMethod> methodsToRevisit() {
+ public ProgramMethodSet methodsToRevisit() {
applyDoubleInlining = true;
return doubleInlineCallers;
}
@@ -574,14 +578,14 @@
public static class InlineAction {
- public final DexEncodedMethod target;
+ public final ProgramMethod target;
public final Invoke invoke;
final Reason reason;
private boolean shouldSynthesizeInitClass;
private boolean shouldSynthesizeNullCheckForReceiver;
- InlineAction(DexEncodedMethod target, Invoke invoke, Reason reason) {
+ InlineAction(ProgramMethod target, Invoke invoke, Reason reason) {
this.target = target;
this.invoke = invoke;
this.reason = reason;
@@ -600,7 +604,7 @@
InlineeWithReason buildInliningIR(
AppView<? extends AppInfoWithClassHierarchy> appView,
InvokeMethod invoke,
- DexEncodedMethod context,
+ ProgramMethod context,
InliningIRProvider inliningIRProvider,
LambdaMerger lambdaMerger,
LensCodeRewriter lensCodeRewriter) {
@@ -624,9 +628,9 @@
// building, and therefore, we do not need to do anything here. Upon writing, we will use the
// flag "declared synchronized" instead of "synchronized".
boolean shouldSynthesizeMonitorEnterExit =
- target.accessFlags.isSynchronized() && options.isGeneratingClassFiles();
+ target.getDefinition().isSynchronized() && options.isGeneratingClassFiles();
boolean isSynthesizingNullCheckForReceiverUsingMonitorEnter =
- shouldSynthesizeMonitorEnterExit && !target.isStatic();
+ shouldSynthesizeMonitorEnterExit && !target.getDefinition().isStatic();
if (shouldSynthesizeNullCheckForReceiver
&& !isSynthesizingNullCheckForReceiverUsingMonitorEnter) {
synthesizeNullCheckForReceiver(appView, code);
@@ -709,11 +713,11 @@
// If this is a static method, then the class object will act as the lock, so we load it
// using a const-class instruction.
Value lockValue;
- if (target.isStatic()) {
+ if (target.getDefinition().isStatic()) {
lockValue =
code.createValue(
TypeElement.fromDexType(dexItemFactory.objectType, definitelyNotNull(), appView));
- monitorEnterBlockIterator.add(new ConstClass(lockValue, target.holder()));
+ monitorEnterBlockIterator.add(new ConstClass(lockValue, target.getHolderType()));
} else {
lockValue = entryBlock.getInstructions().getFirst().asArgument().outValue();
}
@@ -739,7 +743,7 @@
}
}
- if (inliningIRProvider.shouldApplyCodeRewritings(code.method())) {
+ if (inliningIRProvider.shouldApplyCodeRewritings(target)) {
assert lensCodeRewriter != null;
lensCodeRewriter.rewrite(code, target);
}
@@ -762,7 +766,7 @@
InstructionListIterator iterator = initClassBlock.listIterator(code);
iterator.setInsertionPosition(entryBlock.exit().getPosition());
- iterator.add(new InitClass(code.createValue(TypeElement.getInt()), target.holder()));
+ iterator.add(new InitClass(code.createValue(TypeElement.getInt()), target.getHolderType()));
}
private void synthesizeNullCheckForReceiver(AppView<?> appView, IRCode code) {
@@ -842,17 +846,17 @@
}
public static class InliningInfo {
- public final DexEncodedMethod target;
+ public final ProgramMethod target;
public final DexType receiverType; // null, if unknown
- public InliningInfo(DexEncodedMethod target, DexType receiverType) {
+ public InliningInfo(ProgramMethod target, DexType receiverType) {
this.target = target;
this.receiverType = receiverType;
}
}
public void performForcedInlining(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
Map<? extends InvokeMethod, InliningInfo> invokesToInline,
InliningIRProvider inliningIRProvider) {
@@ -860,8 +864,9 @@
performInliningImpl(
oracle, oracle, method, code, OptimizationFeedbackIgnore.getInstance(), inliningIRProvider);
}
+
public void performInlining(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
MethodProcessor methodProcessor) {
@@ -874,7 +879,7 @@
}
public void performInlining(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
@@ -883,7 +888,6 @@
DefaultInliningOracle oracle =
createDefaultOracle(
method,
- code,
methodProcessor,
options.inliningInstructionLimit,
options.inliningInstructionAllowance - numberOfInstructions(code),
@@ -904,14 +908,12 @@
}
public DefaultInliningOracle createDefaultOracle(
- DexEncodedMethod method,
- IRCode code,
+ ProgramMethod method,
MethodProcessor methodProcessor,
int inliningInstructionLimit,
int inliningInstructionAllowance) {
return createDefaultOracle(
method,
- code,
methodProcessor,
inliningInstructionLimit,
inliningInstructionAllowance,
@@ -919,8 +921,7 @@
}
public DefaultInliningOracle createDefaultOracle(
- DexEncodedMethod method,
- IRCode code,
+ ProgramMethod method,
MethodProcessor methodProcessor,
int inliningInstructionLimit,
int inliningInstructionAllowance,
@@ -930,7 +931,6 @@
this,
inliningReasonStrategy,
method,
- code,
methodProcessor,
inliningInstructionLimit,
inliningInstructionAllowance);
@@ -939,7 +939,7 @@
private void performInliningImpl(
InliningStrategy strategy,
InliningOracle oracle,
- DexEncodedMethod context,
+ ProgramMethod context,
IRCode code,
OptimizationFeedback feedback,
InliningIRProvider inliningIRProvider) {
@@ -964,16 +964,19 @@
if (current.isInvokeMethod()) {
InvokeMethod invoke = current.asInvokeMethod();
// TODO(b/142116551): This should be equivalent to invoke.lookupSingleTarget()!
- DexEncodedMethod singleTarget = oracle.lookupSingleTarget(invoke, context.holder());
+ ProgramMethod singleTarget = oracle.lookupSingleTarget(invoke, context);
if (singleTarget == null) {
- WhyAreYouNotInliningReporter.handleInvokeWithUnknownTarget(invoke, appView, context);
+ WhyAreYouNotInliningReporter.handleInvokeWithUnknownTarget(
+ invoke, appView, context.getDefinition());
continue;
}
+ DexEncodedMethod singleTargetMethod = singleTarget.getDefinition();
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter =
oracle.isForcedInliningOracle()
? NopWhyAreYouNotInliningReporter.getInstance()
- : WhyAreYouNotInliningReporter.createFor(singleTarget, appView, context);
+ : WhyAreYouNotInliningReporter.createFor(
+ singleTargetMethod, appView, context.getDefinition());
InlineAction action =
oracle.computeInlining(
invoke,
@@ -1012,8 +1015,8 @@
strategy.ensureMethodProcessed(singleTarget, inlinee.code, feedback);
// Make sure constructor inlining is legal.
- assert !singleTarget.isClassInitializer();
- if (singleTarget.isInstanceInitializer()
+ assert !singleTargetMethod.isClassInitializer();
+ if (singleTargetMethod.isInstanceInitializer()
&& !strategy.canInlineInstanceInitializer(
inlinee.code, whyAreYouNotInliningReporter)) {
assert whyAreYouNotInliningReporter.unsetReasonHasBeenReportedFlag();
@@ -1041,22 +1044,22 @@
getDowncastTypeIfNeeded(strategy, invoke, singleTarget));
if (inlinee.reason == Reason.SINGLE_CALLER) {
- feedback.markInlinedIntoSingleCallSite(singleTarget);
+ feedback.markInlinedIntoSingleCallSite(singleTargetMethod);
}
classInitializationAnalysis.notifyCodeHasChanged();
postProcessInlineeBlocks(code, inlinee.code, blockIterator, block);
// The synthetic and bridge flags are maintained only if the inlinee has also these flags.
- if (context.accessFlags.isBridge() && !inlinee.code.method().accessFlags.isBridge()) {
- context.accessFlags.demoteFromBridge();
+ if (context.getDefinition().isBridge() && !inlinee.code.method().accessFlags.isBridge()) {
+ context.getDefinition().accessFlags.demoteFromBridge();
}
- if (context.accessFlags.isSynthetic()
+ if (context.getDefinition().accessFlags.isSynthetic()
&& !inlinee.code.method().accessFlags.isSynthetic()) {
- context.accessFlags.demoteFromSynthetic();
+ context.getDefinition().accessFlags.demoteFromSynthetic();
}
- context.copyMetadata(singleTarget);
+ context.getDefinition().copyMetadata(singleTargetMethod);
if (inlineeMayHaveInvokeMethod && options.applyInliningToInlinee) {
if (inlineeStack.size() + 1 > options.applyInliningToInlineeMaxDepth
@@ -1103,7 +1106,7 @@
}
private DexType getDowncastTypeIfNeeded(
- InliningStrategy strategy, InvokeMethod invoke, DexEncodedMethod target) {
+ InliningStrategy strategy, InvokeMethod invoke, ProgramMethod target) {
if (invoke.isInvokeMethodWithReceiver()) {
// If the invoke has a receiver but the actual type of the receiver is different
// from the computed target holder, inlining requires a downcast of the receiver.
@@ -1113,8 +1116,8 @@
// method holder as a fallback.
receiverType = invoke.getInvokedMethod().holder;
}
- if (!appView.appInfo().isSubtype(receiverType, target.holder())) {
- return target.holder();
+ if (!appView.appInfo().isSubtype(receiverType, target.getHolderType())) {
+ return target.getHolderType();
}
}
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 6f4570f..a9e4736 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -4,8 +4,7 @@
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
@@ -20,18 +19,18 @@
boolean isForcedInliningOracle();
// TODO(b/142116551): This should be equivalent to invoke.lookupSingleTarget(appView, context)!
- DexEncodedMethod lookupSingleTarget(InvokeMethod invoke, DexType context);
+ ProgramMethod lookupSingleTarget(InvokeMethod invoke, ProgramMethod context);
boolean passesInliningConstraints(
InvokeMethod invoke,
- DexEncodedMethod candidate,
+ ProgramMethod candidate,
Reason reason,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
InlineAction computeInlining(
InvokeMethod invoke,
- DexEncodedMethod singleTarget,
- DexEncodedMethod context,
+ ProgramMethod singleTarget,
+ ProgramMethod context,
ClassInitializationAnalysis classInitializationAnalysis,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
index 0f22b14..cda0a6b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.ir.optimize;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -43,8 +43,7 @@
/** Inform the strategy that the inlinee has been inlined. */
void markInlined(InlineeWithReason inlinee);
- void ensureMethodProcessed(
- DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback);
+ void ensureMethodProcessed(ProgramMethod target, IRCode inlinee, OptimizationFeedback feedback);
DexType getReceiverTypeIfKnown(InvokeMethod invoke);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index e6dcbbe..458f4b1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -225,7 +226,7 @@
private void rewriteInvokeMethodWithConstantValues(
IRCode code,
- DexType context,
+ ProgramMethod context,
Set<Value> affectedValues,
ListIterator<BasicBlock> blocks,
InstructionListIterator iterator,
@@ -235,7 +236,7 @@
if (!invokedHolder.isClassType()) {
return;
}
- DexEncodedMethod target = current.lookupSingleTarget(appView, context);
+ DexEncodedMethod target = current.lookupSingleTarget(appView, context.getHolderType());
if (target != null && target.isInstanceInitializer()) {
// Member value propagation does not apply to constructors. Removing a call to a constructor
// that is marked as having no side effects could lead to verification errors, due to
@@ -302,10 +303,10 @@
current.setOutValue(null);
if (current.isInvokeMethodWithReceiver()) {
- replaceInstructionByNullCheckIfPossible(current, iterator, context);
+ replaceInstructionByNullCheckIfPossible(current, iterator, context.getHolderType());
} else if (current.isInvokeStatic()) {
replaceInstructionByInitClassIfPossible(
- current, target.holder(), code, iterator, context);
+ current, target.holder(), code, iterator, context.getHolderType());
}
// Insert the definition of the replacement.
@@ -390,7 +391,7 @@
&& singleValue.asSingleFieldValue().getField() == field) {
return;
}
- if (singleValue.isMaterializableInContext(appView, code.method().holder())) {
+ if (singleValue.isMaterializableInContext(appView, code.context())) {
BasicBlock block = current.getBlock();
DexType context = code.method().holder();
Position position = current.getPosition();
@@ -534,7 +535,7 @@
ListIterator<BasicBlock> blockIterator,
Set<Value> affectedValues,
Predicate<BasicBlock> blockTester) {
- DexType context = code.method().holder();
+ ProgramMethod context = code.context();
while (blockIterator.hasNext()) {
BasicBlock block = blockIterator.next();
if (!blockTester.test(block)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 6a05911..2b9456a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.optimize;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
@@ -12,10 +11,10 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -29,6 +28,7 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -65,9 +65,11 @@
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.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -77,7 +79,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.Set;
import java.util.function.Consumer;
/**
@@ -94,24 +95,25 @@
* <li>Second, {@link Outliner#selectMethodsForOutlining()} is called to retain the lists of
* methods found in the first step that are large enough (see {@link InternalOptions#outline}
* {@link OutlineOptions#threshold}), and the methods to be further analyzed for outlining is
- * returned by {@link Outliner#getMethodsSelectedForOutlining}. Each selected method is then
+ * returned by {@link Outliner#buildMethodsSelectedForOutlining}. Each selected method is then
* converted back to IR and passed to {@link Outliner#identifyOutlineSites(IRCode)}, which
* then stores concrete outlining candidates in {@link Outliner#outlineSites}.
* <li>Third, {@link Outliner#buildOutlinerClass(DexType)} is called to construct the <em>outline
* support class</em> containing a static helper method for each outline candidate that occurs
* frequently enough. Each selected method is then converted to IR, passed to {@link
- * Outliner#applyOutliningCandidate(IRCode)} to perform the outlining, and
- * converted back to the output format (DEX or CF).
+ * Outliner#applyOutliningCandidate(IRCode)} to perform the outlining, and converted back to
+ * the output format (DEX or CF).
* </ul>
*/
public class Outliner {
/** Result of first step (see {@link Outliner#createOutlineMethodIdentifierGenerator()}. */
- private final List<List<DexEncodedMethod>> candidateMethodLists = new ArrayList<>();
+ private final List<List<ProgramMethod>> candidateMethodLists = new ArrayList<>();
/** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
- private final Set<DexEncodedMethod> methodsSelectedForOutlining = Sets.newIdentityHashSet();
+ private final LongLivedProgramMethodSetBuilder methodsSelectedForOutlining =
+ new LongLivedProgramMethodSetBuilder();
/** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
- private final Map<Outline, List<DexEncodedMethod>> outlineSites = new HashMap<>();
+ private final Map<Outline, List<ProgramMethod>> outlineSites = new HashMap<>();
/** Result of third step (see {@link Outliner#buildOutlinerClass(DexType)}. */
private final Map<Outline, DexMethod> generatedOutlines = new HashMap<>();
@@ -716,7 +718,7 @@
// replacing.
abstract private class OutlineSpotter {
- final DexEncodedMethod method;
+ final ProgramMethod method;
final BasicBlock block;
// instructionArrayCache is block.getInstructions() copied to an ArrayList.
private List<Instruction> instructionArrayCache = null;
@@ -733,7 +735,7 @@
int returnValueUsersLeft;
int pendingNewInstanceIndex = -1;
- OutlineSpotter(DexEncodedMethod method, BasicBlock block) {
+ OutlineSpotter(ProgramMethod method, BasicBlock block) {
this.method = method;
this.block = block;
reset(0);
@@ -862,7 +864,7 @@
// See whether we could move this invoke somewhere else. We reuse the logic from inlining
// here, as the constraints are the same.
ConstraintWithTarget constraint =
- invoke.inliningConstraint(inliningConstraints, method.holder());
+ invoke.inliningConstraint(inliningConstraints, method.getHolderType());
if (constraint != ConstraintWithTarget.ALWAYS) {
return false;
}
@@ -1133,12 +1135,10 @@
// TODO(sgjesse): This does not take several usages in the same method into account.
private class OutlineMethodIdentifier extends OutlineSpotter {
- private final Map<Outline, List<DexEncodedMethod>> candidateMap;
+ private final Map<Outline, List<ProgramMethod>> candidateMap;
OutlineMethodIdentifier(
- DexEncodedMethod method,
- BasicBlock block,
- Map<Outline, List<DexEncodedMethod>> candidateMap) {
+ ProgramMethod method, BasicBlock block, Map<Outline, List<ProgramMethod>> candidateMap) {
super(method, block);
this.candidateMap = candidateMap;
}
@@ -1150,8 +1150,8 @@
}
}
- private List<DexEncodedMethod> addOutlineMethodList(Outline outline) {
- List<DexEncodedMethod> result = new ArrayList<>();
+ private List<ProgramMethod> addOutlineMethodList(Outline outline) {
+ List<ProgramMethod> result = new ArrayList<>();
candidateMethodLists.add(result);
return result;
}
@@ -1159,7 +1159,7 @@
private class OutlineSiteIdentifier extends OutlineSpotter {
- OutlineSiteIdentifier(DexEncodedMethod method, BasicBlock block) {
+ OutlineSiteIdentifier(ProgramMethod method, BasicBlock block) {
super(method, block);
}
@@ -1184,7 +1184,7 @@
ListIterator<BasicBlock> blocksIterator,
BasicBlock block,
List<Integer> toRemove) {
- super(code.method(), block);
+ super(code.context(), block);
this.code = code;
this.blocksIterator = blocksIterator;
this.toRemove = toRemove;
@@ -1259,7 +1259,9 @@
/** When assertions are enabled, remove method from the outline's list. */
private boolean removeMethodFromOutlineList(Outline outline) {
synchronized (outlineSites) {
- assert outlineSites.get(outline).remove(method);
+ assert ListUtils.removeFirstMatch(
+ outlineSites.get(outline),
+ element -> element.getDefinition() == method.getDefinition());
}
return true;
}
@@ -1275,14 +1277,14 @@
// out-value of invokes to null), this map must not be used except for identifying methods
// potentially relevant to outlining. OutlineMethodIdentifier will add method lists to
// candidateMethodLists whenever it adds an entry to candidateMap.
- Map<Outline, List<DexEncodedMethod>> candidateMap = new HashMap<>();
+ Map<Outline, List<ProgramMethod>> candidateMap = new HashMap<>();
assert candidateMethodLists.isEmpty();
assert outlineMethodIdentifierGenerator == null;
outlineMethodIdentifierGenerator =
code -> {
assert !code.method().getCode().isOutlineCode();
for (BasicBlock block : code.blocks) {
- new OutlineMethodIdentifier(code.method(), block, candidateMap).process();
+ new OutlineMethodIdentifier(code.context(), block, candidateMap).process();
}
};
}
@@ -1296,38 +1298,30 @@
public void identifyOutlineSites(IRCode code) {
assert !code.method().getCode().isOutlineCode();
- DexClass clazz = asProgramClassOrNull(appView.definitionFor(code.method().holder()));
- assert clazz != null;
- if (clazz == null) {
- return;
- }
+ DexProgramClass clazz = code.context().getHolder();
if (appView.options().featureSplitConfiguration != null
- && appView.options().featureSplitConfiguration.isInFeature(clazz.asProgramClass())) {
+ && appView.options().featureSplitConfiguration.isInFeature(clazz)) {
return;
}
-
for (BasicBlock block : code.blocks) {
- new OutlineSiteIdentifier(code.method(), block).process();
+ new OutlineSiteIdentifier(code.context(), block).process();
}
}
public boolean selectMethodsForOutlining() {
- assert methodsSelectedForOutlining.size() == 0;
- assert outlineSites.size() == 0;
- for (List<DexEncodedMethod> outlineMethods : candidateMethodLists) {
+ assert methodsSelectedForOutlining.isEmpty();
+ assert outlineSites.isEmpty();
+ for (List<ProgramMethod> outlineMethods : candidateMethodLists) {
if (outlineMethods.size() >= appView.options().outline.threshold) {
- for (DexEncodedMethod outlineMethod : outlineMethods) {
- methodsSelectedForOutlining.add(
- appView.graphLense().mapDexEncodedMethod(outlineMethod, appView));
- }
+ methodsSelectedForOutlining.addAll(outlineMethods);
}
}
candidateMethodLists.clear();
- return methodsSelectedForOutlining.size() > 0;
+ return !methodsSelectedForOutlining.isEmpty();
}
- public Set<DexEncodedMethod> getMethodsSelectedForOutlining() {
- return methodsSelectedForOutlining;
+ public ProgramMethodSet buildMethodsSelectedForOutlining() {
+ return methodsSelectedForOutlining.build(appView);
}
public DexProgramClass buildOutlinerClass(DexType type) {
@@ -1345,7 +1339,7 @@
DexString methodName =
appView.dexItemFactory().createString(OutlineOptions.METHOD_PREFIX + count);
DexMethod method = outline.buildMethod(type, methodName);
- List<DexEncodedMethod> sites = outlineSites.get(outline);
+ List<ProgramMethod> sites = outlineSites.get(outline);
assert !sites.isEmpty();
direct[count] =
new DexEncodedMethod(
@@ -1356,7 +1350,7 @@
new OutlineCode(outline),
true);
if (appView.options().isGeneratingClassFiles()) {
- direct[count].upgradeClassFileVersion(sites.get(0).getClassFileVersion());
+ direct[count].upgradeClassFileVersion(sites.get(0).getDefinition().getClassFileVersion());
}
generatedOutlines.put(outline, method);
count++;
@@ -1393,10 +1387,10 @@
}
private List<Outline> selectOutlines() {
- assert outlineSites.size() > 0;
+ assert !outlineSites.isEmpty();
assert candidateMethodLists.isEmpty();
List<Outline> result = new ArrayList<>();
- for (Entry<Outline, List<DexEncodedMethod>> entry : outlineSites.entrySet()) {
+ for (Entry<Outline, List<ProgramMethod>> entry : outlineSites.entrySet()) {
if (entry.getValue().size() >= appView.options().outline.threshold) {
result.add(entry.getKey());
}
@@ -1603,10 +1597,9 @@
}
@Override
- public IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- OutlineSourceCode source = new OutlineSourceCode(outline, encodedMethod.method);
- return IRBuilder.create(encodedMethod, appView, source, origin)
- .build(encodedMethod);
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ OutlineSourceCode source = new OutlineSourceCode(outline, method.getReference());
+ return IRBuilder.create(method, appView, source, origin).build(method);
}
@Override
@@ -1615,7 +1608,12 @@
}
@Override
- public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index ccb328e..1ba460e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.analysis.value.SingleValue;
@@ -54,7 +55,7 @@
private static final int MAX_CAPACITY_PER_BLOCK = 50;
private final AppView<?> appView;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
private final IRCode code;
// Values that may require type propagation.
@@ -69,7 +70,7 @@
public RedundantFieldLoadElimination(AppView<?> appView, IRCode code) {
this.appView = appView;
- this.method = code.method();
+ this.method = code.context();
this.code = code;
}
@@ -105,7 +106,7 @@
private final SingleValue value;
private MaterializableValue(SingleValue value) {
- assert value.isMaterializableInContext(appView.withLiveness(), method.holder());
+ assert value.isMaterializableInContext(appView.withLiveness(), method);
this.value = value;
}
@@ -153,14 +154,14 @@
if (appView.enableWholeProgramOptimizations()) {
return appView.appInfo().resolveField(field);
}
- if (field.holder == method.holder()) {
+ if (field.holder == method.getHolderType()) {
return appView.definitionFor(field);
}
return null;
}
public void run() {
- DexType context = method.holder();
+ DexType context = method.getHolderType();
Reference2IntMap<BasicBlock> pendingNormalSuccessors = new Reference2IntOpenHashMap<>();
for (BasicBlock block : code.blocks) {
if (!block.hasUniqueNormalSuccessor()) {
@@ -213,7 +214,8 @@
FieldAndObject fieldAndObject = new FieldAndObject(field, object);
ExistingValue value = new ExistingValue(instancePut.value());
if (isFinal(definition)) {
- assert method.isInstanceInitializer() || verifyWasInstanceInitializer();
+ assert method.getDefinition().isInstanceInitializer()
+ || verifyWasInstanceInitializer();
activeState.putFinalInstanceField(fieldAndObject, value);
} else {
activeState.putNonFinalInstanceField(fieldAndObject, value);
@@ -244,7 +246,7 @@
killNonFinalActiveFields(staticPut);
ExistingValue value = new ExistingValue(staticPut.value());
if (definition.isFinal()) {
- assert method.isClassInitializer();
+ assert method.getDefinition().isClassInitializer();
activeState.putFinalStaticField(field, value);
} else {
activeState.putNonFinalStaticField(field, value);
@@ -332,11 +334,11 @@
private boolean verifyWasInstanceInitializer() {
VerticallyMergedClasses verticallyMergedClasses = appView.verticallyMergedClasses();
assert verticallyMergedClasses != null;
- assert verticallyMergedClasses.isTarget(method.holder());
+ assert verticallyMergedClasses.isTarget(method.getHolderType());
assert appView
.dexItemFactory()
- .isConstructor(appView.graphLense().getOriginalMethodSignature(method.method));
- assert method.getOptimizationInfo().forceInline();
+ .isConstructor(appView.graphLense().getOriginalMethodSignature(method.getReference()));
+ assert method.getDefinition().getOptimizationInfo().forceInline();
return true;
}
@@ -346,7 +348,7 @@
return;
}
- DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.holder());
+ DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType());
if (singleTarget == null || !singleTarget.isInstanceInitializer()) {
killAllNonFinalActiveFields();
return;
@@ -374,7 +376,7 @@
activeState.putNonFinalInstanceField(fieldAndObject, new ExistingValue(value));
} else if (info.isSingleValue()) {
SingleValue value = info.asSingleValue();
- if (value.isMaterializableInContext(appView.withLiveness(), method.holder())) {
+ if (value.isMaterializableInContext(appView.withLiveness(), method)) {
Value object = invoke.getReceiver().getAliasedValue();
FieldAndObject fieldAndObject = new FieldAndObject(field.field, object);
activeState.putNonFinalInstanceField(fieldAndObject, new MaterializableValue(value));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index c60da19..1f410ef 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -56,7 +56,7 @@
}
DexType type = null;
if (current.isInvokeVirtual()) {
- type = getTypeForGetClass( appView, context, current.asInvokeVirtual());
+ type = getTypeForGetClass(appView, context, current.asInvokeVirtual());
} else if (current.isInvokeStatic()) {
type = getTypeForClassForName(
appView, classInitializationAnalysis, context, current.asInvokeStatic());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
index d5d51e1..7bec65e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -94,7 +94,7 @@
List<DexEncodedField> switchMapFields = clazz.staticFields().stream()
.filter(this::maybeIsSwitchMap).collect(Collectors.toList());
if (!switchMapFields.isEmpty()) {
- IRCode initializer = clazz.getClassInitializer().buildIR(appView, clazz.origin);
+ IRCode initializer = clazz.getProgramClassInitializer().buildIR(appView);
switchMapFields.forEach(field -> extractSwitchMap(field, initializer));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 798b820..e7104f3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -166,7 +167,7 @@
CodeRewriter codeRewriter,
StringOptimizer stringOptimizer,
EnumValueOptimizer enumValueOptimizer,
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
@@ -297,7 +298,8 @@
codeRewriter.simplifyControlFlow(code);
// If a method was inlined we may see more trivial computation/conversion of String.
boolean isDebugMode =
- appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive();
+ appView.options().debug
+ || method.getDefinition().getOptimizationInfo().isReachabilitySensitive();
if (!isDebugMode) {
// Reflection/string optimization 3. trivial conversion/computation on const-string
stringOptimizer.computeTrivialOperationsOnConstString(code);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
index da76b7b..3feac87 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerCostAnalysis.java
@@ -10,8 +10,8 @@
import static com.android.tools.r8.ir.code.Opcodes.RETURN;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -44,19 +44,19 @@
boolean willExceedInstructionBudget(
IRCode code,
DexProgramClass eligibleClass,
- Map<InvokeMethod, DexEncodedMethod> directInlinees,
- List<DexEncodedMethod> indirectInlinees) {
+ Map<InvokeMethod, ProgramMethod> directInlinees,
+ List<ProgramMethod> indirectInlinees) {
if (appView.appInfo().alwaysClassInline.contains(eligibleClass.type)) {
return false;
}
- for (DexEncodedMethod inlinee : indirectInlinees) {
+ for (ProgramMethod inlinee : indirectInlinees) {
// We do not have the corresponding invoke instruction for the inlinees that are not called
// directly from `code` (these are called indirectly from one of the methods in
// `directInlinees`). Therefore, we currently choose not to build IR for estimating the number
// of non-materializing instructions, since we cannot cache the IR (it would have the wrong
// position).
- int increment = inlinee.getCode().estimatedSizeForInlining();
+ int increment = inlinee.getDefinition().getCode().estimatedSizeForInlining();
if (exceedsInstructionBudgetAfterIncrement(increment)) {
return true;
}
@@ -67,14 +67,14 @@
int numberOfSeenDirectInlinees = 0;
int numberOfDirectInlinees = directInlinees.size();
for (InvokeMethod invoke : code.<InvokeMethod>instructions(Instruction::isInvokeMethod)) {
- DexEncodedMethod inlinee = directInlinees.get(invoke);
+ ProgramMethod inlinee = directInlinees.get(invoke);
if (inlinee == null) {
// Not a direct inlinee.
continue;
}
IRCode inliningIR = inliningIRProvider.getAndCacheInliningIR(invoke, inlinee);
int increment =
- inlinee.getCode().estimatedSizeForInlining()
+ inlinee.getDefinition().getCode().estimatedSizeForInlining()
- estimateNumberOfNonMaterializingInstructions(invoke, inliningIR);
assert increment >= 0;
if (exceedsInstructionBudgetAfterIncrement(increment)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 9a76a99..59e9a94 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.classinliner;
+import static com.android.tools.r8.graph.DexEncodedMethod.asProgramMethodOrNull;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.google.common.base.Predicates.alwaysFalse;
@@ -16,7 +17,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -57,6 +58,7 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -89,7 +91,7 @@
private final Inliner inliner;
private final Function<DexClass, EligibilityStatus> isClassEligible;
private final MethodProcessor methodProcessor;
- private final DexEncodedMethod method;
+ private final ProgramMethod method;
private final Instruction root;
private Value eligibleInstance;
@@ -98,14 +100,14 @@
private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
new IdentityHashMap<>();
- private final Set<DexEncodedMethod> indirectMethodCallsOnInstance = Sets.newIdentityHashSet();
+ private final ProgramMethodSet indirectMethodCallsOnInstance = ProgramMethodSet.create();
private final Map<InvokeMethod, InliningInfo> extraMethodCalls
= new IdentityHashMap<>();
private final List<Pair<InvokeMethod, Integer>> unusedArguments
= new ArrayList<>();
- private final Map<InvokeMethod, DexEncodedMethod> directInlinees = new IdentityHashMap<>();
- private final List<DexEncodedMethod> indirectInlinees = new ArrayList<>();
+ private final Map<InvokeMethod, ProgramMethod> directInlinees = new IdentityHashMap<>();
+ private final List<ProgramMethod> indirectInlinees = new ArrayList<>();
// Sets of values that must/may be an alias of the "root" instance (including the root instance
// itself).
@@ -116,7 +118,7 @@
Inliner inliner,
Function<DexClass, EligibilityStatus> isClassEligible,
MethodProcessor methodProcessor,
- DexEncodedMethod method,
+ ProgramMethod method,
Instruction root) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
@@ -132,11 +134,11 @@
return eligibleClass;
}
- Map<InvokeMethod, DexEncodedMethod> getDirectInlinees() {
+ Map<InvokeMethod, ProgramMethod> getDirectInlinees() {
return directInlinees;
}
- List<DexEncodedMethod> getIndirectInlinees() {
+ List<ProgramMethod> getIndirectInlinees() {
return indirectInlinees;
}
@@ -160,7 +162,7 @@
if (eligibleClass.classInitializationMayHaveSideEffects(
appView,
// Types that are a super type of the current context are guaranteed to be initialized.
- type -> appView.isSubtype(method.holder(), type).isTrue(),
+ type -> appView.isSubtype(method.getHolderType(), type).isTrue(),
Sets.newIdentityHashSet())) {
return EligibilityStatus.HAS_CLINIT;
}
@@ -170,7 +172,7 @@
assert root.isStaticGet();
StaticGet staticGet = root.asStaticGet();
- if (staticGet.instructionMayHaveSideEffects(appView, method.holder())) {
+ if (staticGet.instructionMayHaveSideEffects(appView, method.getHolderType())) {
return EligibilityStatus.RETRIEVAL_MAY_HAVE_SIDE_EFFECTS;
}
DexEncodedField field = appView.appInfo().resolveField(staticGet.getField());
@@ -265,15 +267,17 @@
if (user.isInvokeMethod()) {
InvokeMethod invokeMethod = user.asInvokeMethod();
- DexEncodedMethod singleTarget = invokeMethod.lookupSingleTarget(appView, method.holder());
- if (singleTarget == null) {
+ DexEncodedMethod singleTargetMethod =
+ invokeMethod.lookupSingleTarget(appView, method.getHolderType());
+ if (singleTargetMethod == null) {
return user; // Not eligible.
}
- if (isEligibleLibraryMethodCall(invokeMethod, singleTarget)) {
+ if (isEligibleLibraryMethodCall(invokeMethod, singleTargetMethod)) {
continue;
}
+ ProgramMethod singleTarget = singleTargetMethod.asProgramMethod(appView);
if (!isEligibleSingleTarget(singleTarget)) {
return user; // Not eligible.
}
@@ -463,8 +467,11 @@
throw new IllegalClassInlinerStateException();
}
+ ProgramMethod singleTargetMethod =
+ new ProgramMethod(
+ appView.definitionForHolder(singleTarget).asProgramClass(), singleTarget);
methodCallsOnInstance.put(
- invoke, new InliningInfo(singleTarget, root.asNewInstance().clazz));
+ invoke, new InliningInfo(singleTargetMethod, root.asNewInstance().clazz));
break;
}
}
@@ -506,8 +513,7 @@
continue;
}
- DexEncodedMethod singleTarget =
- invoke.lookupSingleTarget(appView, code.method().holder());
+ ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, method);
if (singleTarget == null || !indirectMethodCallsOnInstance.contains(singleTarget)) {
throw new IllegalClassInlinerStateException();
}
@@ -568,7 +574,7 @@
continue;
}
- DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.holder());
+ DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType());
if (singleTarget != null) {
Predicate<InvokeMethod> noSideEffectsPredicate =
dexItemFactory.libraryMethodsWithoutSideEffects.getOrDefault(
@@ -618,7 +624,7 @@
throw new Unreachable(
"Unexpected usage left in method `"
- + method.method.toSourceString()
+ + method.toSourceString()
+ "` after inlining: "
+ user);
}
@@ -650,7 +656,7 @@
throw new Unreachable(
"Unexpected usage left in method `"
- + method.method.toSourceString()
+ + method.toSourceString()
+ "` after inlining: "
+ user);
}
@@ -689,7 +695,7 @@
if (!user.isInstancePut()) {
throw new Unreachable(
"Unexpected usage left in method `"
- + method.method.toSourceString()
+ + method.toSourceString()
+ "` after field reads removed: "
+ user);
}
@@ -699,7 +705,7 @@
if (field == null) {
throw new Unreachable(
"Unexpected field write left in method `"
- + method.method.toSourceString()
+ + method.toSourceString()
+ "` after field reads removed: "
+ user);
}
@@ -707,8 +713,7 @@
}
}
- private InliningInfo isEligibleConstructorCall(
- InvokeDirect invoke, DexEncodedMethod singleTarget) {
+ private InliningInfo isEligibleConstructorCall(InvokeDirect invoke, ProgramMethod singleTarget) {
assert dexItemFactory.isConstructor(invoke.getInvokedMethod());
assert isEligibleSingleTarget(singleTarget);
@@ -735,7 +740,7 @@
// Check that the `eligibleInstance` does not escape via the constructor.
InstanceInitializerInfo instanceInitializerInfo =
- singleTarget.getOptimizationInfo().getInstanceInitializerInfo();
+ singleTarget.getDefinition().getOptimizationInfo().getInstanceInitializerInfo();
if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
return null;
}
@@ -746,21 +751,22 @@
if (parent == null) {
return null;
}
- DexEncodedMethod encodedParent = appView.definitionFor(parent);
+ ProgramMethod encodedParent = asProgramMethodOrNull(appView.definitionFor(parent), appView);
if (encodedParent == null) {
return null;
}
if (methodProcessor.isProcessedConcurrently(encodedParent)) {
return null;
}
- if (!encodedParent.isInliningCandidate(
+ DexEncodedMethod encodedParentMethod = encodedParent.getDefinition();
+ if (!encodedParentMethod.isInliningCandidate(
method,
Reason.SIMPLE,
appView.appInfo(),
NopWhyAreYouNotInliningReporter.getInstance())) {
return null;
}
- parent = encodedParent.getOptimizationInfo().getInstanceInitializerInfo().getParent();
+ parent = encodedParentMethod.getOptimizationInfo().getInstanceInitializerInfo().getParent();
}
return new InliningInfo(singleTarget, eligibleClass.type);
@@ -848,7 +854,7 @@
private InliningInfo isEligibleDirectVirtualMethodCall(
InvokeMethodWithReceiver invoke,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Set<Instruction> indirectUsers,
Supplier<InliningOracle> defaultOracle) {
assert isEligibleSingleTarget(singleTarget);
@@ -862,7 +868,7 @@
}
// TODO(b/141719453): Should not constrain library overrides if all instantiations are inlined.
- if (singleTarget.isLibraryMethodOverride().isTrue()) {
+ if (singleTarget.getDefinition().isLibraryMethodOverride().isTrue()) {
InliningOracle inliningOracle = defaultOracle.get();
if (!inliningOracle.passesInliningConstraints(
invoke, singleTarget, Reason.SIMPLE, NopWhyAreYouNotInliningReporter.getInstance())) {
@@ -880,18 +886,20 @@
}
ClassInlinerEligibilityInfo eligibility =
- singleTarget.getOptimizationInfo().getClassInlinerEligibility();
+ singleTarget.getDefinition().getOptimizationInfo().getClassInlinerEligibility();
if (eligibility.callsReceiver.size() > 1) {
return null;
}
if (!eligibility.callsReceiver.isEmpty()) {
assert eligibility.callsReceiver.get(0).getFirst() == Invoke.Type.VIRTUAL;
DexMethod indirectlyInvokedMethod = eligibility.callsReceiver.get(0).getSecond();
- DexEncodedMethod indirectSingleTarget =
- appView.appInfo().resolveMethod(eligibleClass, indirectlyInvokedMethod).getSingleTarget();
- if (indirectSingleTarget == null) {
+ ResolutionResult resolutionResult =
+ appView.appInfo().resolveMethod(eligibleClass, indirectlyInvokedMethod);
+ if (!resolutionResult.isSingleResolution()) {
return null;
}
+ ProgramMethod indirectSingleTarget =
+ resolutionResult.asSingleResolution().getResolutionPair().asProgramMethod();
if (!isEligibleIndirectVirtualMethodCall(indirectlyInvokedMethod, indirectSingleTarget)) {
return null;
}
@@ -902,17 +910,19 @@
}
private boolean isEligibleIndirectVirtualMethodCall(DexMethod invokedMethod) {
- DexEncodedMethod singleTarget =
- appView.appInfo().resolveMethod(eligibleClass, invokedMethod).getSingleTarget();
+ ProgramMethod singleTarget =
+ asProgramMethodOrNull(
+ appView.appInfo().resolveMethod(eligibleClass, invokedMethod).getSingleTarget(),
+ appView);
return isEligibleIndirectVirtualMethodCall(invokedMethod, singleTarget);
}
private boolean isEligibleIndirectVirtualMethodCall(
- DexMethod invokedMethod, DexEncodedMethod singleTarget) {
+ DexMethod invokedMethod, ProgramMethod singleTarget) {
if (!isEligibleSingleTarget(singleTarget)) {
return false;
}
- if (singleTarget.isLibraryMethodOverride().isTrue()) {
+ if (singleTarget.getDefinition().isLibraryMethodOverride().isTrue()) {
return false;
}
return isEligibleVirtualMethodCall(
@@ -926,7 +936,7 @@
private boolean isEligibleVirtualMethodCall(
InvokeMethodWithReceiver invoke,
DexMethod callee,
- DexEncodedMethod singleTarget,
+ ProgramMethod singleTarget,
Predicate<ClassInlinerEligibilityInfo> eligibilityAcceptanceCheck) {
assert isEligibleSingleTarget(singleTarget);
@@ -939,14 +949,14 @@
return false;
}
- if (!singleTarget.isNonPrivateVirtualMethod()) {
+ if (!singleTarget.getDefinition().isNonPrivateVirtualMethod()) {
return false;
}
- if (method == singleTarget) {
+ if (method.getDefinition() == singleTarget.getDefinition()) {
return false; // Don't inline itself.
}
- MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
+ MethodOptimizationInfo optimizationInfo = singleTarget.getDefinition().getOptimizationInfo();
ClassInlinerEligibilityInfo eligibility = optimizationInfo.getClassInlinerEligibility();
if (eligibility == null) {
return false;
@@ -1013,7 +1023,7 @@
// -- method itself can be inlined
//
private boolean isExtraMethodCallEligible(
- InvokeMethod invoke, DexEncodedMethod singleTarget, Supplier<InliningOracle> defaultOracle) {
+ InvokeMethod invoke, ProgramMethod singleTarget, Supplier<InliningOracle> defaultOracle) {
// Don't consider constructor invocations and super calls, since we don't want to forcibly
// inline them.
assert isExtraMethodCall(invoke);
@@ -1035,10 +1045,11 @@
}
}
- MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
+ MethodOptimizationInfo optimizationInfo = singleTarget.getDefinition().getOptimizationInfo();
// Go through all arguments, see if all usages of eligibleInstance are good.
- if (!isEligibleParameterUsages(invoke, arguments, singleTarget, defaultOracle)) {
+ if (!isEligibleParameterUsages(
+ invoke, arguments, singleTarget.getDefinition(), defaultOracle)) {
return false;
}
@@ -1155,16 +1166,23 @@
}
// Check if the method is inline-able by standard inliner.
- DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.holder());
+ DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method.getHolderType());
if (singleTarget == null) {
return false;
}
+ DexProgramClass holder = asProgramClassOrNull(appView.definitionForHolder(singleTarget));
+ if (holder == null) {
+ return false;
+ }
+
+ ProgramMethod singleTargetMethod = new ProgramMethod(holder, singleTarget);
+
InliningOracle oracle = defaultOracle.get();
InlineAction inlineAction =
oracle.computeInlining(
invoke,
- singleTarget,
+ singleTargetMethod,
method,
ClassInitializationAnalysis.trivial(),
NopWhyAreYouNotInliningReporter.getInstance());
@@ -1188,15 +1206,12 @@
return initializerInfo.receiverNeverEscapesOutsideConstructorChain();
}
- private boolean exemptFromInstructionLimit(DexEncodedMethod inlinee) {
- DexType inlineeHolder = inlinee.holder();
- DexClass inlineeClass = appView.definitionFor(inlineeHolder);
- assert inlineeClass != null;
- KotlinClassLevelInfo kotlinInfo = inlineeClass.getKotlinInfo();
+ private boolean exemptFromInstructionLimit(ProgramMethod inlinee) {
+ KotlinClassLevelInfo kotlinInfo = inlinee.getHolder().getKotlinInfo();
return kotlinInfo.isSyntheticClass() && kotlinInfo.asSyntheticClass().isLambda();
}
- private void markSizeForInlining(InvokeMethod invoke, DexEncodedMethod inlinee) {
+ private void markSizeForInlining(InvokeMethod invoke, ProgramMethod inlinee) {
assert !methodProcessor.isProcessedConcurrently(inlinee);
if (!exemptFromInstructionLimit(inlinee)) {
if (invoke != null) {
@@ -1207,18 +1222,20 @@
}
}
- private boolean isEligibleSingleTarget(DexEncodedMethod singleTarget) {
+ private boolean isEligibleSingleTarget(ProgramMethod singleTarget) {
if (singleTarget == null) {
return false;
}
- if (!singleTarget.isProgramMethod(appView)) {
- return false;
- }
if (methodProcessor.isProcessedConcurrently(singleTarget)) {
return false;
}
- if (!singleTarget.isInliningCandidate(
- method, Reason.SIMPLE, appView.appInfo(), NopWhyAreYouNotInliningReporter.getInstance())) {
+ if (!singleTarget
+ .getDefinition()
+ .isInliningCandidate(
+ method,
+ Reason.SIMPLE,
+ appView.appInfo(),
+ NopWhyAreYouNotInliningReporter.getInstance())) {
// If `singleTarget` is not an inlining candidate, we won't be able to inline it here.
//
// Note that there may be some false negatives here since the method may
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index cf9c904..06c2894 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -53,6 +53,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -73,7 +74,7 @@
private final DexItemFactory factory;
// Map the enum candidates with their dependencies, i.e., the methods to reprocess for the given
// enum if the optimization eventually decides to unbox it.
- private final Map<DexType, Set<DexEncodedMethod>> enumsUnboxingCandidates;
+ private final Map<DexType, ProgramMethodSet> enumsUnboxingCandidates;
private EnumUnboxingRewriter enumUnboxerRewriter;
@@ -184,11 +185,11 @@
}
if (!eligibleEnums.isEmpty()) {
for (DexType eligibleEnum : eligibleEnums) {
- Set<DexEncodedMethod> dependencies = enumsUnboxingCandidates.get(eligibleEnum);
+ ProgramMethodSet dependencies = enumsUnboxingCandidates.get(eligibleEnum);
// If dependencies is null, it means the enum is not eligible (It has been marked as
// unboxable by this thread or another one), so we do not need to record dependencies.
if (dependencies != null) {
- dependencies.add(code.method());
+ dependencies.add(code.context());
}
}
}
@@ -313,7 +314,6 @@
appView
.appInfo()
.rewrittenWithLens(appView.appInfo().app().asDirect(), enumUnboxingLens));
- classStaticizer.filterCandidates();
// Update optimization info.
feedback.fixupOptimizationInfos(
appView,
@@ -609,9 +609,9 @@
}
@Override
- public Set<DexEncodedMethod> methodsToRevisit() {
- Set<DexEncodedMethod> toReprocess = Sets.newIdentityHashSet();
- for (Set<DexEncodedMethod> methods : enumsUnboxingCandidates.values()) {
+ public ProgramMethodSet methodsToRevisit() {
+ ProgramMethodSet toReprocess = ProgramMethodSet.create();
+ for (ProgramMethodSet methods : enumsUnboxingCandidates.values()) {
toReprocess.addAll(methods);
}
return toReprocess;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
index 5412037..d138d95 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -18,9 +18,8 @@
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer.Reason;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
class EnumUnboxingCandidateAnalysis {
@@ -28,7 +27,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final EnumUnboxer enumUnboxer;
private final DexItemFactory factory;
- private Map<DexType, Set<DexEncodedMethod>> enumToUnboxCandidates = new ConcurrentHashMap<>();
+ private Map<DexType, ProgramMethodSet> enumToUnboxCandidates = new ConcurrentHashMap<>();
EnumUnboxingCandidateAnalysis(AppView<AppInfoWithLiveness> appView, EnumUnboxer enumUnboxer) {
this.appView = appView;
@@ -36,10 +35,10 @@
factory = appView.dexItemFactory();
}
- Map<DexType, Set<DexEncodedMethod>> findCandidates() {
+ Map<DexType, ProgramMethodSet> findCandidates() {
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (isEnumUnboxingCandidate(clazz)) {
- enumToUnboxCandidates.put(clazz.type, Sets.newConcurrentHashSet());
+ enumToUnboxCandidates.put(clazz.type, ProgramMethodSet.createConcurrent());
}
}
removeEnumsInAnnotations();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java
index 953514d..c94be2e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java
@@ -4,13 +4,13 @@
package com.android.tools.r8.ir.optimize.enums;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeDirect;
@@ -54,8 +54,8 @@
if (!clazz.accessFlags.isEnum() || clazz.isNotProgramClass() || !clazz.hasClassInitializer()) {
return;
}
- DexEncodedMethod initializer = clazz.getClassInitializer();
- IRCode code = initializer.getCode().buildIR(initializer, appView, clazz.origin);
+ ProgramMethod initializer = clazz.getProgramClassInitializer();
+ IRCode code = initializer.buildIR(appView);
LinkedHashMap<DexField, EnumValueInfo> enumValueInfoMap = new LinkedHashMap<>();
for (StaticPut staticPut : code.<StaticPut>instructions(Instruction::isStaticPut)) {
if (staticPut.getField().type != clazz.type) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 14a3800..23b74b1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -289,8 +289,7 @@
return;
}
- boolean synchronizedVirtualMethod =
- method.accessFlags.isSynchronized() && method.isVirtualMethod();
+ boolean synchronizedVirtualMethod = method.isSynchronized() && method.isVirtualMethod();
feedback.setClassInlinerEligibility(
method,
@@ -1042,7 +1041,7 @@
return;
}
boolean mayHaveSideEffects;
- if (method.accessFlags.isSynchronized()) {
+ if (method.isSynchronized()) {
// If the method is synchronized then it acquires a lock.
mayHaveSideEffects = true;
} else if (method.isInstanceInitializer() && hasNonTrivialFinalizeMethod(context)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
index 5c45a37..ae543a2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/DefaultInliningReasonStrategy.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.conversion.CallSiteInformation;
import com.android.tools.r8.ir.optimize.Inliner;
@@ -29,25 +31,27 @@
@Override
public Reason computeInliningReason(
- InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
- if (target.getOptimizationInfo().forceInline()
+ InvokeMethod invoke, ProgramMethod target, ProgramMethod context) {
+ DexEncodedMethod targetMethod = target.getDefinition();
+ DexMethod targetReference = target.getReference();
+ if (targetMethod.getOptimizationInfo().forceInline()
|| (appView.appInfo().hasLiveness()
- && appView.withLiveness().appInfo().forceInline.contains(target.method))) {
- assert !appView.appInfo().neverInline.contains(target.method);
+ && appView.withLiveness().appInfo().forceInline.contains(targetReference))) {
+ assert !appView.appInfo().neverInline.contains(targetReference);
return Reason.FORCE;
}
if (appView.appInfo().hasLiveness()
- && appView.withLiveness().appInfo().alwaysInline.contains(target.method)) {
+ && appView.withLiveness().appInfo().alwaysInline.contains(targetReference)) {
return Reason.ALWAYS;
}
if (appView.options().disableInliningOfLibraryMethodOverrides
- && target.isLibraryMethodOverride().isTrue()) {
+ && targetMethod.isLibraryMethodOverride().isTrue()) {
// This method will always have an implicit call site from the library, so we won't be able to
// remove it after inlining even if we have single or dual call site information from the
// program.
return Reason.SIMPLE;
}
- if (callSiteInformation.hasSingleCallSite(target.method)) {
+ if (callSiteInformation.hasSingleCallSite(target)) {
return Reason.SINGLE_CALLER;
}
if (isDoubleInliningTarget(target)) {
@@ -56,11 +60,11 @@
return Reason.SIMPLE;
}
- private boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
+ private boolean isDoubleInliningTarget(ProgramMethod candidate) {
// 10 is found from measuring.
- if (callSiteInformation.hasDoubleCallSite(candidate.method)
+ if (callSiteInformation.hasDoubleCallSite(candidate)
|| inliner.isDoubleInlineSelectedTarget(candidate)) {
- return candidate.getCode().estimatedSizeForInliningAtMost(10);
+ return candidate.getDefinition().getCode().estimatedSizeForInliningAtMost(10);
}
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
index 2b4c072..ae23a74 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/FixedInliningReasonStrategy.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.inliner;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -18,7 +18,7 @@
@Override
public Reason computeInliningReason(
- InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context) {
+ InvokeMethod invoke, ProgramMethod target, ProgramMethod context) {
return reason;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
index 608c41f..85cb117 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.optimize.inliner;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Position;
@@ -18,32 +18,32 @@
public class InliningIRProvider {
private final AppView<?> appView;
- private final DexEncodedMethod context;
+ private final ProgramMethod context;
private final ValueNumberGenerator valueNumberGenerator;
private final MethodProcessor methodProcessor;
private final Map<InvokeMethod, IRCode> cache = new IdentityHashMap<>();
public InliningIRProvider(
- AppView<?> appView, DexEncodedMethod context, IRCode code, MethodProcessor methodProcessor) {
+ AppView<?> appView, ProgramMethod context, IRCode code, MethodProcessor methodProcessor) {
this.appView = appView;
this.context = context;
this.valueNumberGenerator = code.valueNumberGenerator;
this.methodProcessor = methodProcessor;
}
- public IRCode getInliningIR(InvokeMethod invoke, DexEncodedMethod method) {
+ public IRCode getInliningIR(InvokeMethod invoke, ProgramMethod method) {
IRCode cached = cache.remove(invoke);
if (cached != null) {
return cached;
}
Position position = Position.getPositionForInlining(appView, invoke, context);
- Origin origin = appView.appInfo().originFor(method.holder());
+ Origin origin = method.getOrigin();
return method.buildInliningIR(
context, appView, valueNumberGenerator, position, origin, methodProcessor);
}
- public IRCode getAndCacheInliningIR(InvokeMethod invoke, DexEncodedMethod method) {
+ public IRCode getAndCacheInliningIR(InvokeMethod invoke, ProgramMethod method) {
IRCode inliningIR = getInliningIR(invoke, method);
cacheInliningIR(invoke, inliningIR);
return inliningIR;
@@ -59,7 +59,7 @@
return true;
}
- public boolean shouldApplyCodeRewritings(DexEncodedMethod method) {
+ public boolean shouldApplyCodeRewritings(ProgramMethod method) {
return methodProcessor.shouldApplyCodeRewritings(method);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
index 6e8e1aa..f2ae52a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningReasonStrategy.java
@@ -4,12 +4,11 @@
package com.android.tools.r8.ir.optimize.inliner;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
public interface InliningReasonStrategy {
- Reason computeInliningReason(
- InvokeMethod invoke, DexEncodedMethod target, DexEncodedMethod context);
+ Reason computeInliningReason(InvokeMethod invoke, ProgramMethod target, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
index eb8b742..92635f2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
@@ -6,11 +6,11 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstClass;
@@ -158,19 +158,19 @@
private final LambdaTypeVisitor lambdaChecker;
// Specify the context of the current instruction: method/code/blocks/instructions.
- public final DexEncodedMethod method;
+ public final ProgramMethod method;
public final IRCode code;
public final ListIterator<BasicBlock> blocks;
private InstructionListIterator instructions;
// The inlining context (caller), if any.
- private final DexEncodedMethod context;
+ private final ProgramMethod context;
CodeProcessor(
AppView<AppInfoWithLiveness> appView,
Function<DexType, Strategy> strategyProvider,
LambdaTypeVisitor lambdaChecker,
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code) {
this(appView, strategyProvider, lambdaChecker, method, code, null);
}
@@ -179,9 +179,9 @@
AppView<AppInfoWithLiveness> appView,
Function<DexType, Strategy> strategyProvider,
LambdaTypeVisitor lambdaChecker,
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
- DexEncodedMethod context) {
+ ProgramMethod context) {
this.appView = appView;
this.strategyProvider = strategyProvider;
this.factory = appView.dexItemFactory();
@@ -218,7 +218,7 @@
private boolean shouldRewrite(DexType type) {
// Rewrite references to lambda classes if we are outside the class.
- return type != (context != null ? context : method).holder();
+ return type != (context != null ? context : method).getHolderType();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 63d2c1d..2a5e9cd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -10,12 +10,14 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater;
@@ -50,6 +52,8 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
@@ -67,7 +71,6 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Function;
-import java.util.stream.Collectors;
// Merging lambda classes into single lambda group classes. There are three flavors
// of lambdas we are dealing with:
@@ -97,19 +100,19 @@
private abstract static class Mode {
void rewriteCode(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
Inliner inliner,
- DexEncodedMethod context,
+ ProgramMethod context,
InliningIRProvider provider) {}
- void analyzeCode(DexEncodedMethod method, IRCode code) {}
+ void analyzeCode(ProgramMethod method, IRCode code) {}
}
private class AnalyzeMode extends Mode {
@Override
- void analyzeCode(DexEncodedMethod method, IRCode code) {
+ void analyzeCode(ProgramMethod method, IRCode code) {
new AnalysisStrategy(method, code).processCode();
}
}
@@ -128,27 +131,24 @@
@Override
void rewriteCode(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
Inliner inliner,
- DexEncodedMethod context,
+ ProgramMethod context,
InliningIRProvider provider) {
- DexProgramClass clazz = appView.definitionFor(method.holder()).asProgramClass();
- assert clazz != null;
-
- LambdaGroup lambdaGroup = lambdaGroups.get(clazz);
+ LambdaGroup lambdaGroup = lambdaGroups.get(method.getHolder());
if (lambdaGroup == null) {
// Only rewrite the methods that have not been synthesized for the lambda group classes.
new ApplyStrategy(method, code, context, optimizationInfoFixer).processCode();
return;
}
- if (method.isInitializer()) {
+ if (method.getDefinition().isInitializer()) {
// Should not require rewriting.
return;
}
- assert method.isNonPrivateVirtualMethod();
+ assert method.getDefinition().isNonPrivateVirtualMethod();
assert context == null;
Map<InvokeVirtual, InliningInfo> invokesToInline = new IdentityHashMap<>();
@@ -160,9 +160,10 @@
ResolutionResult resolution =
appView.appInfo().resolveMethod(holder, invokedMethod, false);
assert resolution.isSingleResolution();
- DexEncodedMethod singleTarget = resolution.getSingleTarget();
+ ProgramMethod singleTarget =
+ resolution.asSingleResolution().getResolutionPair().asProgramMethod();
assert singleTarget != null;
- invokesToInline.put(invoke, new InliningInfo(singleTarget, singleTarget.holder()));
+ invokesToInline.put(invoke, new InliningInfo(singleTarget, singleTarget.getHolderType()));
}
}
@@ -194,7 +195,8 @@
// we mark a method for further processing, and then invalidate the only lambda referenced
// from it. In this case we will reprocess method that does not need patching, but it
// should not be happening very frequently and we ignore possible overhead.
- private final Set<DexEncodedMethod> methodsToReprocess = Sets.newIdentityHashSet();
+ private final LongLivedProgramMethodSetBuilder methodsToReprocess =
+ new LongLivedProgramMethodSetBuilder();
private final AppView<AppInfoWithLiveness> appView;
private final Kotlin kotlin;
@@ -236,7 +238,7 @@
return lambdas.get(lambda);
}
- private synchronized void queueForProcessing(DexEncodedMethod method) {
+ private synchronized void queueForProcessing(ProgramMethod method) {
methodsToReprocess.add(method);
}
@@ -291,7 +293,7 @@
* <li>in APPLY mode does nothing.
* </ol>
*/
- public final void analyzeCode(DexEncodedMethod method, IRCode code) {
+ public final void analyzeCode(ProgramMethod method, IRCode code) {
if (mode != null) {
mode.analyzeCode(method, code);
}
@@ -308,10 +310,10 @@
* </ol>
*/
public final void rewriteCode(
- DexEncodedMethod method, IRCode code, Inliner inliner, MethodProcessor methodProcessor) {
+ ProgramMethod method, IRCode code, Inliner inliner, MethodProcessor methodProcessor) {
if (mode != null) {
mode.rewriteCode(
- method,
+ code.context(),
code,
inliner,
null,
@@ -320,12 +322,12 @@
}
/**
- * Similar to {@link #rewriteCode(DexEncodedMethod, IRCode, Inliner, MethodProcessor)}, but for
+ * Similar to {@link #rewriteCode(ProgramMethod, IRCode, Inliner, MethodProcessor)}, but for
* rewriting code for inlining. The {@param context} is the caller that {@param method} is being
* inlined into.
*/
public final void rewriteCodeForInlining(
- DexEncodedMethod method, IRCode code, DexEncodedMethod context, InliningIRProvider provider) {
+ ProgramMethod method, IRCode code, ProgramMethod context, InliningIRProvider provider) {
if (mode != null) {
mode.rewriteCode(method, code, null, context, provider);
}
@@ -453,12 +455,11 @@
if (methodsToReprocess.isEmpty()) {
return;
}
- Set<DexEncodedMethod> methods =
- methodsToReprocess.stream()
- .map(method -> appView.graphLense().mapDexEncodedMethod(method, appView))
- .collect(Collectors.toSet());
+ ProgramMethodSet methods = methodsToReprocess.build(appView);
converter.processMethodsConcurrently(methods, executorService);
- assert methods.stream().allMatch(DexEncodedMethod::isProcessed);
+ assert methods.stream()
+ .map(DexClassAndMethod::getDefinition)
+ .allMatch(DexEncodedMethod::isProcessed);
}
private void analyzeClass(DexProgramClass clazz) {
@@ -491,7 +492,7 @@
}
private final class AnalysisStrategy extends CodeProcessor {
- private AnalysisStrategy(DexEncodedMethod method, IRCode code) {
+ private AnalysisStrategy(ProgramMethod method, IRCode code) {
super(
LambdaMerger.this.appView,
LambdaMerger.this::strategyProvider,
@@ -543,9 +544,9 @@
private final Set<Value> typeAffectedValues = Sets.newIdentityHashSet();
private ApplyStrategy(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
- DexEncodedMethod context,
+ ProgramMethod context,
LambdaMergerOptimizationInfoFixer optimizationInfoFixer) {
super(
LambdaMerger.this.appView,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
index 4d79186..112b37c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
@@ -53,8 +53,8 @@
// static class initializer.
return field.name == context.kotlin.functional.kotlinStyleLambdaInstanceName
&& lambda == field.type
- && context.factory.isClassConstructor(context.method.method)
- && context.method.holder() == lambda;
+ && context.method.getDefinition().isClassInitializer()
+ && context.method.getHolderType() == lambda;
}
@Override
@@ -69,10 +69,10 @@
@Override
public boolean isValidInstanceFieldWrite(CodeProcessor context, DexField field) {
DexType lambda = field.holder;
- DexMethod method = context.method.method;
+ DexMethod method = context.method.getReference();
assert group.containsLambda(lambda);
// Support writes to capture instance fields inside lambda constructor only.
- return method.holder == lambda && context.factory.isConstructor(method);
+ return method.holder == lambda && context.method.getDefinition().isInstanceInitializer();
}
@Override
@@ -100,7 +100,7 @@
// Allow calls to a constructor from other classes if the lambda is singleton,
// otherwise allow such a call only from the same class static initializer.
boolean isSingletonLambda = group.isStateless() && group.isSingletonLambda(lambda);
- return (isSingletonLambda == (context.method.holder() == lambda))
+ return (isSingletonLambda == (context.method.getHolderType() == lambda))
&& invoke.isInvokeDirect()
&& context.factory.isConstructor(method)
&& CaptureSignature.getCaptureSignature(method.proto.parameters).equals(group.id().capture);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index 3311e1d..041cf09 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.staticizer;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
@@ -15,6 +17,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
@@ -31,11 +34,13 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
@@ -64,7 +69,6 @@
final AtomicInteger fieldWrites = new AtomicInteger();
// Number of instances created.
final AtomicInteger instancesCreated = new AtomicInteger();
- final Set<DexEncodedMethod> referencedFrom = Sets.newConcurrentHashSet();
final AtomicReference<DexEncodedMethod> constructor = new AtomicReference<>();
final AtomicReference<DexEncodedMethod> getter = new AtomicReference<>();
@@ -86,8 +90,8 @@
return singletonField.holder();
}
- DexClass hostClass() {
- DexClass hostClass = appView.definitionFor(hostType());
+ DexProgramClass hostClass() {
+ DexProgramClass hostClass = asProgramClassOrNull(appView.definitionFor(hostType()));
assert hostClass != null;
return hostClass;
}
@@ -96,17 +100,11 @@
candidates.remove(candidate.type);
return null;
}
-
- void filterMethods() {
- Set<DexEncodedMethod> newReferencedFrom = Sets.newIdentityHashSet();
- for (DexEncodedMethod dexEncodedMethod : referencedFrom) {
- newReferencedFrom.add(appView.graphLense().mapDexEncodedMethod(dexEncodedMethod, appView));
- }
- referencedFrom.clear();
- referencedFrom.addAll(newReferencedFrom);
- }
}
+ final Map<CandidateInfo, LongLivedProgramMethodSetBuilder> referencedFrom =
+ new IdentityHashMap<>();
+
// The map storing all the potential candidates for staticizing.
final ConcurrentHashMap<DexType, CandidateInfo> candidates = new ConcurrentHashMap<>();
@@ -218,10 +216,11 @@
// or field defined in the class.
//
// NOTE: can be called concurrently.
- public final void examineMethodCode(DexEncodedMethod method, IRCode code) {
+ public final void examineMethodCode(IRCode code) {
+ ProgramMethod method = code.context();
Set<Instruction> alreadyProcessed = Sets.newIdentityHashSet();
- CandidateInfo receiverClassCandidateInfo = candidates.get(method.holder());
+ CandidateInfo receiverClassCandidateInfo = candidates.get(method.getHolderType());
Value receiverValue = code.getThis(); // NOTE: is null for static methods.
if (receiverClassCandidateInfo != null) {
if (receiverValue != null) {
@@ -229,26 +228,28 @@
// which we will check later), check if all the references to 'this' are valid
// (the call will invalidate the candidate if some of them are not valid).
analyzeAllValueUsers(
- receiverClassCandidateInfo, receiverValue, factory.isConstructor(method.method));
+ receiverClassCandidateInfo,
+ receiverValue,
+ factory.isConstructor(method.getReference()));
// If the candidate is still valid, ignore all instructions
// we treat as valid usages on receiver.
- if (candidates.get(method.holder()) != null) {
+ if (candidates.get(method.getHolderType()) != null) {
alreadyProcessed.addAll(receiverValue.uniqueUsers());
}
} else {
// We are inside a static method of candidate class.
// Check if this is a valid getter of the singleton field.
- if (method.method.proto.returnType == method.holder()) {
+ if (method.getDefinition().returnType() == method.getHolderType()) {
List<Instruction> examined = isValidGetter(receiverClassCandidateInfo, code);
if (examined != null) {
DexEncodedMethod getter = receiverClassCandidateInfo.getter.get();
if (getter == null) {
- receiverClassCandidateInfo.getter.set(method);
+ receiverClassCandidateInfo.getter.set(method.getDefinition());
// Except for static-get and return, iterate other remaining instructions if any.
alreadyProcessed.addAll(examined);
} else {
- assert getter != method;
+ assert getter != method.getDefinition();
// Not sure how to deal with many getters.
receiverClassCandidateInfo.invalidate();
}
@@ -274,7 +275,8 @@
if (instruction.isNewInstance()) {
// Check the class being initialized against valid staticizing candidates.
NewInstance newInstance = instruction.asNewInstance();
- CandidateInfo candidateInfo = processInstantiation(method, iterator, newInstance);
+ CandidateInfo candidateInfo =
+ processInstantiation(method.getDefinition(), iterator, newInstance);
if (candidateInfo != null) {
alreadyProcessed.addAll(newInstance.outValue().aliasedUsers());
// For host class initializers having eligible instantiation we also want to
@@ -282,14 +284,16 @@
// This must guarantee that removing field access will not result in missing side
// effects, otherwise we can still staticize, but cannot remove singleton reads.
while (iterator.hasNext()) {
- if (!isAllowedInHostClassInitializer(method.holder(), iterator.next(), code)) {
+ if (!isAllowedInHostClassInitializer(method.getHolderType(), iterator.next(), code)) {
candidateInfo.preserveRead.set(true);
iterator.previous();
break;
}
// Ignore just read instruction.
}
- candidateInfo.referencedFrom.add(method);
+ referencedFrom
+ .computeIfAbsent(candidateInfo, ignore -> new LongLivedProgramMethodSetBuilder())
+ .add(method);
}
continue;
}
@@ -309,7 +313,9 @@
// Check the field being read: make sure all usages are valid.
CandidateInfo info = processStaticFieldRead(instruction.asStaticGet());
if (info != null) {
- info.referencedFrom.add(method);
+ referencedFrom
+ .computeIfAbsent(info, ignore -> new LongLivedProgramMethodSetBuilder())
+ .add(method);
// If the candidate is still valid, ignore all usages in further analysis.
Value value = instruction.outValue();
if (value != null) {
@@ -323,7 +329,9 @@
// Check if it is a static singleton getter.
CandidateInfo info = processInvokeStatic(instruction.asInvokeStatic());
if (info != null) {
- info.referencedFrom.add(method);
+ referencedFrom
+ .computeIfAbsent(info, ignore -> new LongLivedProgramMethodSetBuilder())
+ .add(method);
// If the candidate is still valid, ignore all usages in further analysis.
Value value = instruction.outValue();
if (value != null) {
@@ -659,17 +667,6 @@
return false;
}
- // Methods may have their signature changed in-between the IR processing rounds, leading to
- // duplicates where one version is the outdated version. Remove these.
- // This also ensures no unboxed enum are staticized, if that would be the case, then
- // the candidate would need to be removed from the candidate list.
- public void filterCandidates() {
- for (Map.Entry<DexType, CandidateInfo> entry : candidates.entrySet()) {
- assert !appView.unboxedEnums().containsEnum(entry.getKey());
- entry.getValue().filterMethods();
- }
- }
-
// Perform staticizing candidates:
//
// 1. After filtering candidates based on usage, finalize the list of candidates by
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 845a01c..1e7fb3c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.staticizer;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import com.android.tools.r8.graph.AppView;
@@ -17,6 +18,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -36,10 +38,11 @@
import com.android.tools.r8.ir.optimize.CodeRewriter;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.staticizer.ClassStaticizer.CandidateInfo;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.TraversalContinuation;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
@@ -66,13 +69,15 @@
private final ClassStaticizer classStaticizer;
private final IRConverter converter;
+ private final ProgramMethodSet methodsToReprocess = ProgramMethodSet.create();
+
// Optimization order matters, hence a collection that preserves orderings.
private final Map<DexEncodedMethod, ImmutableList.Builder<BiConsumer<IRCode, MethodProcessor>>>
processingQueue = new IdentityHashMap<>();
- private final Set<DexEncodedMethod> referencingExtraMethods = Sets.newIdentityHashSet();
+ private final ProgramMethodSet referencingExtraMethods = ProgramMethodSet.create();
private final Map<DexEncodedMethod, CandidateInfo> hostClassInits = new IdentityHashMap<>();
- private final Set<DexEncodedMethod> methodsToBeStaticized = Sets.newIdentityHashSet();
+ private final ProgramMethodSet methodsToBeStaticized = ProgramMethodSet.create();
private final Map<DexField, CandidateInfo> singletonFields = new IdentityHashMap<>();
private final Map<DexMethod, CandidateInfo> singletonGetters = new IdentityHashMap<>();
private final Map<DexType, DexType> candidateToHostMapping = new IdentityHashMap<>();
@@ -89,14 +94,21 @@
final void run(OptimizationFeedback feedback, ExecutorService executorService)
throws ExecutionException {
// Filter out candidates based on the information we collected while examining methods.
- finalEligibilityCheck();
+ Map<CandidateInfo, ProgramMethodSet> materializedReferencedFromCollections =
+ finalEligibilityCheck();
// Prepare interim data.
- prepareCandidates();
+ prepareCandidates(materializedReferencedFromCollections);
// Enqueue all host class initializers (only remove instantiations).
+ ProgramMethodSet hostClassInitMethods = ProgramMethodSet.create();
+ hostClassInits
+ .values()
+ .forEach(
+ candidateInfo ->
+ hostClassInitMethods.add(candidateInfo.hostClass().getProgramClassInitializer()));
enqueueMethodsWithCodeOptimizations(
- hostClassInits.keySet(),
+ hostClassInitMethods,
optimizations ->
optimizations
.add(this::removeCandidateInstantiation)
@@ -114,13 +126,13 @@
// TODO(b/140767158): Merge the remaining part below.
// Convert instance methods into static methods with an extra parameter.
- Set<DexEncodedMethod> methods = staticizeMethodSymbols();
+ ProgramMethodSet methods = staticizeMethodSymbols();
// Process all other methods that may reference singleton fields and call methods on them.
// (Note that we exclude the former instance methods, but include new static methods created as
// a result of staticizing.)
methods.addAll(referencingExtraMethods);
- methods.addAll(hostClassInits.keySet());
+ methods.addAll(hostClassInitMethods);
enqueueMethodsWithCodeOptimizations(
methods,
optimizations ->
@@ -131,13 +143,17 @@
// Process queued methods with associated optimizations
processMethodsConcurrently(feedback, executorService);
+
+ // Clear all candidate information now that all candidates have been staticized.
+ classStaticizer.candidates.clear();
}
- private void finalEligibilityCheck() {
+ private Map<CandidateInfo, ProgramMethodSet> finalEligibilityCheck() {
+ Map<CandidateInfo, ProgramMethodSet> materializedReferencedFromCollections =
+ new IdentityHashMap<>();
Set<Phi> visited = Sets.newIdentityHashSet();
Set<Phi> trivialPhis = Sets.newIdentityHashSet();
- Iterator<Entry<DexType, CandidateInfo>> it =
- classStaticizer.candidates.entrySet().iterator();
+ Iterator<Entry<DexType, CandidateInfo>> it = classStaticizer.candidates.entrySet().iterator();
while (it.hasNext()) {
Entry<DexType, CandidateInfo> entry = it.next();
DexType candidateType = entry.getKey();
@@ -185,33 +201,41 @@
}
// CHECK: references to 'this' in instance methods are fixable.
- boolean fixableThisPointer = true;
- for (DexEncodedMethod method : candidateClass.methods()) {
- if (method.isStatic() || factory().isConstructor(method.method)) {
- continue;
- }
- IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.holder()));
- assert code != null;
- Value thisValue = code.getThis();
- assert thisValue != null;
- visited.clear();
- trivialPhis.clear();
- boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfThis(
- visited, thisValue.uniquePhiUsers(), thisValue, trivialPhis);
- if (thisValue.hasPhiUsers() && !onlyHasTrivialPhis) {
- fixableThisPointer = false;
- break;
- }
- }
- if (!fixableThisPointer) {
+ TraversalContinuation fixableThisPointer =
+ candidateClass.traverseProgramMethods(
+ method -> {
+ IRCode code = method.buildIR(appView);
+ assert code != null;
+ Value thisValue = code.getThis();
+ assert thisValue != null;
+ visited.clear();
+ trivialPhis.clear();
+ boolean onlyHasTrivialPhis =
+ testAndCollectPhisComposedOfThis(
+ visited, thisValue.uniquePhiUsers(), thisValue, trivialPhis);
+ if (thisValue.hasPhiUsers() && !onlyHasTrivialPhis) {
+ return TraversalContinuation.BREAK;
+ }
+ return TraversalContinuation.CONTINUE;
+ },
+ definition -> !definition.isStatic() && !definition.isInstanceInitializer());
+ if (fixableThisPointer.shouldBreak()) {
it.remove();
continue;
}
+ ProgramMethodSet referencedFrom;
+ if (classStaticizer.referencedFrom.containsKey(info)) {
+ referencedFrom = classStaticizer.referencedFrom.remove(info).build(appView);
+ materializedReferencedFromCollections.put(info, referencedFrom);
+ } else {
+ referencedFrom = ProgramMethodSet.empty();
+ }
+
// CHECK: references to field read usages are fixable.
boolean fixableFieldReads = true;
- for (DexEncodedMethod method : info.referencedFrom) {
- IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.holder()));
+ for (ProgramMethod method : referencedFrom) {
+ IRCode code = method.buildIR(appView);
assert code != null;
List<Instruction> singletonUsers =
Streams.stream(code.instructionIterator())
@@ -258,9 +282,11 @@
continue;
}
}
+ return materializedReferencedFromCollections;
}
- private void prepareCandidates() {
+ private void prepareCandidates(
+ Map<CandidateInfo, ProgramMethodSet> materializedReferencedFromCollections) {
Set<DexEncodedMethod> removedInstanceMethods = Sets.newIdentityHashSet();
for (CandidateInfo candidate : classStaticizer.candidates.values()) {
@@ -273,40 +299,46 @@
assert previous == null;
// Collect instance methods to be staticized.
- for (DexEncodedMethod method : candidateClass.methods()) {
- if (!method.isStatic()) {
- removedInstanceMethods.add(method);
- if (!factory().isConstructor(method.method)) {
- methodsToBeStaticized.add(method);
- }
- }
- }
+ candidateClass.forEachProgramMethodMatching(
+ definition -> {
+ if (!definition.isStatic()) {
+ removedInstanceMethods.add(definition);
+ return !definition.isInstanceInitializer();
+ }
+ return false;
+ },
+ methodsToBeStaticized::add);
singletonFields.put(candidate.singletonField.field, candidate);
DexEncodedMethod getter = candidate.getter.get();
if (getter != null) {
singletonGetters.put(getter.method, candidate);
}
- assert validMethods(candidate.referencedFrom);
- referencingExtraMethods.addAll(candidate.referencedFrom);
+ ProgramMethodSet referencedFrom =
+ materializedReferencedFromCollections.getOrDefault(candidate, ProgramMethodSet.empty());
+ assert validMethods(referencedFrom);
+ referencingExtraMethods.addAll(referencedFrom);
}
- referencingExtraMethods.removeAll(removedInstanceMethods);
+ removedInstanceMethods.forEach(referencingExtraMethods::remove);
}
- private boolean validMethods(Set<DexEncodedMethod> referencedFrom) {
- for (DexEncodedMethod dexEncodedMethod : referencedFrom) {
- DexClass clazz = appView.definitionForHolder(dexEncodedMethod.method);
+ private boolean validMethods(ProgramMethodSet referencedFrom) {
+ for (ProgramMethod method : referencedFrom) {
+ DexClass clazz = appView.definitionForHolder(method.getReference());
assert clazz != null;
- assert clazz.lookupMethod(dexEncodedMethod.method) == dexEncodedMethod;
+ assert clazz.lookupMethod(method.getReference()) == method.getDefinition();
}
return true;
}
private void enqueueMethodsWithCodeOptimizations(
- Iterable<DexEncodedMethod> methods,
+ Iterable<ProgramMethod> methods,
Consumer<ImmutableList.Builder<BiConsumer<IRCode, MethodProcessor>>> extension) {
- for (DexEncodedMethod method : methods) {
- extension.accept(processingQueue.computeIfAbsent(method, ignore -> ImmutableList.builder()));
+ for (ProgramMethod method : methods) {
+ methodsToReprocess.add(method);
+ extension.accept(
+ processingQueue.computeIfAbsent(
+ method.getDefinition(), ignore -> ImmutableList.builder()));
}
}
@@ -322,24 +354,27 @@
*/
private void processMethodsConcurrently(
OptimizationFeedback feedback, ExecutorService executorService) throws ExecutionException {
- Set<DexEncodedMethod> wave = processingQueue.keySet();
- OneTimeMethodProcessor methodProcessor = OneTimeMethodProcessor.getInstance(wave);
+ OneTimeMethodProcessor methodProcessor = OneTimeMethodProcessor.getInstance(methodsToReprocess);
methodProcessor.forEachWave(
method ->
- forEachMethod(method, processingQueue.get(method).build(), feedback, methodProcessor),
+ forEachMethod(
+ method,
+ processingQueue.get(method.getDefinition()).build(),
+ feedback,
+ methodProcessor),
executorService);
// TODO(b/140767158): No need to clear if we can do every thing in one go.
+ methodsToReprocess.clear();
processingQueue.clear();
}
// TODO(b/140766440): Should be part or variant of PostProcessor.
private void forEachMethod(
- DexEncodedMethod method,
+ ProgramMethod method,
Collection<BiConsumer<IRCode, MethodProcessor>> codeOptimizations,
OptimizationFeedback feedback,
OneTimeMethodProcessor methodProcessor) {
- Origin origin = appView.appInfo().originFor(method.holder());
- IRCode code = method.buildIR(appView, origin);
+ IRCode code = method.buildIR(appView);
codeOptimizations.forEach(codeOptimization -> codeOptimization.accept(code, methodProcessor));
CodeRewriter.removeAssumeInstructions(appView, code);
converter.removeDeadCodeAndFinalizeIR(method, code, feedback, Timing.empty());
@@ -686,11 +721,11 @@
return field;
}
- private Set<DexEncodedMethod> staticizeMethodSymbols() {
+ private ProgramMethodSet staticizeMethodSymbols() {
BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
BiMap<DexField, DexField> fieldMapping = HashBiMap.create();
- Set<DexEncodedMethod> staticizedMethods = Sets.newIdentityHashSet();
+ ProgramMethodSet staticizedMethods = ProgramMethodSet.create();
for (CandidateInfo candidate : classStaticizer.candidates.values()) {
DexProgramClass candidateClass = candidate.candidate;
@@ -702,7 +737,7 @@
} else if (!factory().isConstructor(method.method)) {
DexEncodedMethod staticizedMethod = method.toStaticMethodWithoutThis();
newDirectMethods.add(staticizedMethod);
- staticizedMethods.add(staticizedMethod);
+ staticizedMethods.createAndAdd(candidateClass, staticizedMethod);
methodMapping.put(method.method, staticizedMethod.method);
}
}
@@ -712,7 +747,7 @@
// Consider moving static members from candidate into host.
DexType hostType = candidate.hostType();
if (candidateClass.type != hostType) {
- DexClass hostClass = appView.definitionFor(hostType);
+ DexProgramClass hostClass = asProgramClassOrNull(appView.definitionFor(hostType));
assert hostClass != null;
if (!classMembersConflict(candidateClass, hostClass)) {
// Move all members of the candidate class into host class.
@@ -736,9 +771,10 @@
}
private void moveMembersIntoHost(
- Set<DexEncodedMethod> staticizedMethods,
+ ProgramMethodSet staticizedMethods,
DexProgramClass candidateClass,
- DexType hostType, DexClass hostClass,
+ DexType hostType,
+ DexProgramClass hostClass,
BiMap<DexMethod, DexMethod> methodMapping,
BiMap<DexField, DexField> fieldMapping) {
candidateToHostMapping.put(candidateClass.type, hostType);
@@ -787,7 +823,7 @@
if (staticizedMethods.remove(method)) {
// Properly update staticized methods to reprocess, i.e., add the corresponding one that
// has just been migrated to the host class.
- staticizedMethods.add(newMethod);
+ staticizedMethods.createAndAdd(hostClass, newMethod);
}
DexMethod originalMethod = methodMapping.inverse().get(method.method);
if (originalMethod == null) {
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 331f14d..9402fbb 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
@@ -6,8 +6,11 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Position;
@@ -35,30 +38,28 @@
}
@Override
- public final IRCode buildIR(DexEncodedMethod encodedMethod, AppView<?> appView, Origin origin) {
- return IRBuilder.create(
- encodedMethod,
- appView,
- getSourceCodeProvider().get(null),
- origin).build(encodedMethod);
+ public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ return IRBuilder.create(method, appView, getSourceCodeProvider().get(null), origin)
+ .build(method);
}
@Override
public IRCode buildInliningIR(
- DexEncodedMethod context,
- DexEncodedMethod encodedMethod,
+ ProgramMethod context,
+ ProgramMethod method,
AppView<?> appView,
ValueNumberGenerator valueNumberGenerator,
Position callerPosition,
Origin origin,
MethodProcessor methodProcessor) {
return IRBuilder.createForInlining(
- encodedMethod,
- appView,
- getSourceCodeProvider().get(callerPosition),
- origin,
- methodProcessor,
- valueNumberGenerator).build(context);
+ method,
+ appView,
+ getSourceCodeProvider().get(callerPosition),
+ origin,
+ methodProcessor,
+ valueNumberGenerator)
+ .build(context);
}
@Override
@@ -67,7 +68,16 @@
}
@Override
- public void registerCodeReferences(DexEncodedMethod method, UseRegistry registry) {
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ internalRegisterCodeReferences(method, registry);
+ }
+
+ private void internalRegisterCodeReferences(DexClassAndMethod method, UseRegistry registry) {
getRegistryCallback().accept(registry);
}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 9f51daa..4f1e59a 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.jar;
import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
+import static org.objectweb.asm.Opcodes.V1_6;
+import static org.objectweb.asm.Opcodes.V1_8;
import com.android.tools.r8.ByteDataView;
import com.android.tools.r8.ClassFileConsumer;
@@ -106,7 +108,7 @@
for (DexProgramClass clazz : application.classes()) {
if (clazz.getSynthesizedFrom().isEmpty()
|| options.isDesugaredLibraryCompilation()
- || options.enableCfInterfaceMethodDesugaring) {
+ || options.cfToCfDesugar) {
writeClass(clazz, consumer, markerString);
} else {
throw new Unimplemented("No support for synthetics in the Java bytecode backend.");
@@ -194,16 +196,16 @@
// which do not have class file version.
assert options.testing.enableForceNestBasedAccessDesugaringForTest
|| options.isDesugaredLibraryCompilation()
- || options.enableCfInterfaceMethodDesugaring;
+ || options.cfToCfDesugar;
// TODO(b/146424042): We may call static methods on interface classes so we have to go for
- // version 52.
- return options.enableCfInterfaceMethodDesugaring ? 52 : 0;
+ // Java 8.
+ return options.cfToCfDesugar ? V1_8 : 0;
}
return method.getClassFileVersion();
}
private int getClassFileVersion(DexProgramClass clazz) {
- int version = clazz.hasClassFileVersion() ? clazz.getInitialClassFileVersion() : 50;
+ int version = clazz.hasClassFileVersion() ? clazz.getInitialClassFileVersion() : V1_6;
for (DexEncodedMethod method : clazz.directMethods()) {
version = Math.max(version, getClassFileVersion(method));
}
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 332477a..2dc287a 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -10,9 +10,7 @@
import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
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.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
@@ -20,6 +18,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexItemBasedValueString;
import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
import com.android.tools.r8.ir.code.ConstString;
@@ -92,12 +91,11 @@
}
}
- public void decoupleIdentifierNameStringsInMethod(DexEncodedMethod method, IRCode code) {
- decoupleIdentifierNameStringsInBlocks(method, code, null);
+ public void decoupleIdentifierNameStringsInMethod(IRCode code) {
+ decoupleIdentifierNameStringsInBlocks(code, null);
}
- public void decoupleIdentifierNameStringsInBlocks(
- DexEncodedMethod method, IRCode code, Set<BasicBlock> blocks) {
+ public void decoupleIdentifierNameStringsInBlocks(IRCode code, Set<BasicBlock> blocks) {
if (!code.metadata().mayHaveConstString()) {
return;
}
@@ -124,11 +122,11 @@
if (instruction.isStaticPut() || instruction.isInstancePut()) {
iterator =
decoupleIdentifierNameStringForFieldPutInstruction(
- code, method, blockIterator, iterator, instruction.asFieldInstruction());
+ code, blockIterator, iterator, instruction.asFieldInstruction());
} else if (instruction.isInvokeMethod()) {
iterator =
decoupleIdentifierNameStringForInvokeInstruction(
- code, method, blockIterator, iterator, instruction.asInvokeMethod());
+ code, blockIterator, iterator, instruction.asInvokeMethod());
}
}
}
@@ -136,7 +134,6 @@
private InstructionListIterator decoupleIdentifierNameStringForFieldPutInstruction(
IRCode code,
- DexEncodedMethod method,
ListIterator<BasicBlock> blocks,
InstructionListIterator iterator,
FieldInstruction instruction) {
@@ -148,13 +145,13 @@
}
Value in = instruction.value();
if (!in.isConstString()) {
- warnUndeterminedIdentifierIfNecessary(field, method.holder(), instruction, null);
+ warnUndeterminedIdentifierIfNecessary(field, code.context(), instruction, null);
return iterator;
}
DexString original = in.getConstInstruction().asConstString().getValue();
DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(field, method.holder(), instruction, original);
+ warnUndeterminedIdentifierIfNecessary(field, code.context(), instruction, original);
return iterator;
}
// Move the cursor back to $fieldPut
@@ -199,7 +196,6 @@
private InstructionListIterator decoupleIdentifierNameStringForInvokeInstruction(
IRCode code,
- DexEncodedMethod method,
ListIterator<BasicBlock> blocks,
InstructionListIterator iterator,
InvokeMethod invoke) {
@@ -213,8 +209,7 @@
if (isReflectionMethod(appView.dexItemFactory(), invokedMethod) || isClassNameComparison) {
DexReference itemBasedString = identifyIdentifier(invoke, appView);
if (itemBasedString == null) {
- DexType context = method.holder();
- warnUndeterminedIdentifierIfNecessary(invokedMethod, context, invoke, null);
+ warnUndeterminedIdentifierIfNecessary(invokedMethod, code.context(), invoke, null);
return iterator;
}
@@ -280,13 +275,13 @@
for (int i = 0; i < ins.size(); i++) {
Value in = ins.get(i);
if (!in.isConstString()) {
- warnUndeterminedIdentifierIfNecessary(invokedMethod, method.holder(), invoke, null);
+ warnUndeterminedIdentifierIfNecessary(invokedMethod, code.context(), invoke, null);
continue;
}
DexString original = in.getConstInstruction().asConstString().getValue();
DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(invokedMethod, method.holder(), invoke, original);
+ warnUndeterminedIdentifierIfNecessary(invokedMethod, code.context(), invoke, original);
continue;
}
// Move the cursor back to $invoke
@@ -361,23 +356,18 @@
}
private void warnUndeterminedIdentifierIfNecessary(
- DexReference member, DexType originHolder, Instruction instruction, DexString original) {
+ DexReference member, ProgramMethod method, Instruction instruction, DexString original) {
assert member.isDexField() || member.isDexMethod();
// Only issue warnings for -identifiernamestring rules explicitly added by the user.
boolean matchedByExplicitRule = identifierNameStrings.getBoolean(member);
if (!matchedByExplicitRule) {
return;
}
- DexClass originClass = appView.definitionFor(originHolder);
- // If the origin is a library class, it is out of developers' control.
- if (originClass != null && originClass.isNotProgramClass()) {
- return;
- }
// Undetermined identifiers matter only if minification is enabled.
if (!appView.options().isMinifying()) {
return;
}
- Origin origin = appView.appInfo().originFor(originHolder);
+ Origin origin = method.getOrigin();
String kind = member.isDexField() ? "field" : "method";
String originalMessage = original == null ? "what identifier string flows to "
: "what '" + original.toString() + "' refers to, which flows to ";
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index d37ef84..45892a2 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -7,12 +7,13 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.optimize.InvokeSingleTargetExtractor.InvokeKind;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ForEachable;
+import com.android.tools.r8.utils.IntBox;
import com.google.common.collect.Sets;
-import java.util.List;
import java.util.Set;
public class VisibilityBridgeRemover {
@@ -24,52 +25,61 @@
}
private void removeUnneededVisibilityBridgesFromClass(DexProgramClass clazz) {
- DexEncodedMethod[] newDirectMethods = removeUnneededVisibilityBridges(clazz.directMethods());
+ DexEncodedMethod[] newDirectMethods =
+ removeUnneededVisibilityBridges(
+ clazz::forEachProgramDirectMethod, clazz.getMethodCollection().numberOfDirectMethods());
if (newDirectMethods != null) {
clazz.setDirectMethods(newDirectMethods);
}
- DexEncodedMethod[] newVirtualMethods = removeUnneededVisibilityBridges(clazz.virtualMethods());
+ DexEncodedMethod[] newVirtualMethods =
+ removeUnneededVisibilityBridges(
+ clazz::forEachProgramVirtualMethod,
+ clazz.getMethodCollection().numberOfVirtualMethods());
if (newVirtualMethods != null) {
clazz.setVirtualMethods(newVirtualMethods);
}
}
- private DexEncodedMethod[] removeUnneededVisibilityBridges(List<DexEncodedMethod> methods) {
- Set<DexEncodedMethod> methodsToBeRemoved = null;
- for (DexEncodedMethod method : methods) {
- if (isUnneededVisibilityBridge(method)) {
- if (methodsToBeRemoved == null) {
- methodsToBeRemoved = Sets.newIdentityHashSet();
- }
- methodsToBeRemoved.add(method);
- }
- }
- if (methodsToBeRemoved != null) {
- Set<DexEncodedMethod> finalMethodsToBeRemoved = methodsToBeRemoved;
- return methods.stream()
- .filter(method -> !finalMethodsToBeRemoved.contains(method))
- .toArray(DexEncodedMethod[]::new);
+ private DexEncodedMethod[] removeUnneededVisibilityBridges(
+ ForEachable<ProgramMethod> methods, int size) {
+ Set<DexEncodedMethod> methodsToBeRemoved = Sets.newIdentityHashSet();
+ methods.forEach(
+ method -> {
+ if (isUnneededVisibilityBridge(method)) {
+ methodsToBeRemoved.add(method.getDefinition());
+ }
+ });
+ if (!methodsToBeRemoved.isEmpty()) {
+ DexEncodedMethod[] newMethods = new DexEncodedMethod[size - methodsToBeRemoved.size()];
+ IntBox i = new IntBox(0);
+ methods.forEach(
+ method -> {
+ if (!methodsToBeRemoved.contains(method.getDefinition())) {
+ newMethods[i.getAndIncrement()] = method.getDefinition();
+ }
+ });
+ return newMethods;
}
return null;
}
- private boolean isUnneededVisibilityBridge(DexEncodedMethod method) {
- if (appView.appInfo().isPinned(method.method)) {
+ private boolean isUnneededVisibilityBridge(ProgramMethod method) {
+ if (appView.appInfo().isPinned(method.getReference())) {
return false;
}
- MethodAccessFlags accessFlags = method.accessFlags;
- if (!accessFlags.isBridge() || accessFlags.isAbstract()) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (!definition.isBridge() || definition.isAbstract()) {
return false;
}
InvokeSingleTargetExtractor targetExtractor =
new InvokeSingleTargetExtractor(appView.dexItemFactory());
- method.getCode().registerCodeReferences(method, targetExtractor);
+ method.registerCodeReferences(targetExtractor);
DexMethod target = targetExtractor.getTarget();
InvokeKind kind = targetExtractor.getKind();
// javac-generated visibility forward bridge method has same descriptor (name, signature and
// return type).
- if (target != null && target.hasSameProtoAndName(method.method)) {
- assert !accessFlags.isPrivate() && !accessFlags.isConstructor();
+ if (target != null && target.hasSameProtoAndName(method.getReference())) {
+ assert !definition.isPrivate() && !definition.isInstanceInitializer();
if (kind == InvokeKind.SUPER) {
// This is a visibility forward, so check for the direct target.
DexEncodedMethod targetMethod =
@@ -77,10 +87,7 @@
if (targetMethod != null && targetMethod.accessFlags.isPublic()) {
if (Log.ENABLED) {
Log.info(
- getClass(),
- "Removing visibility forwarding %s -> %s",
- method.method,
- targetMethod.method);
+ getClass(), "Removing visibility forwarding %s -> %s", method, targetMethod.method);
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java b/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
index c2f5837..3ec10a2 100644
--- a/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
+++ b/src/main/java/com/android/tools/r8/relocator/SimplePackagesRewritingMapper.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
@@ -35,6 +36,15 @@
}
public NamingLens compute(Map<PackageReference, PackageReference> mapping) {
+ // Prefetch all code objects to ensure we have seen all types.
+ // TODO(b/129925954): When updated, there is no need for this prefetch.
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (method.getCode() != null) {
+ method.getCode().asCfCode();
+ }
+ }
+ }
ImmutableMap.Builder<String, String> packingMappings = ImmutableMap.builder();
for (PackageReference key : mapping.keySet()) {
String source = key.getPackageName();
@@ -52,32 +62,36 @@
packingMappings.put(sourceBinary, targetBinary);
DexString sourceDescriptor = appView.dexItemFactory().createString("L" + sourceBinary);
DexString targetDescriptor = appView.dexItemFactory().createString("L" + targetBinary);
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- DexString descriptor = clazz.type.descriptor;
- // Check if descriptor can be a prefix.
- if (descriptor.size <= sourceDescriptor.size) {
- continue;
- }
- // Check if it is either the empty prefix or a fully qualified package.
- if (sourceDescriptor.size != 1
- && descriptor.content[sourceDescriptor.size]
- != DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR) {
- continue;
- }
- // Do a char-by-char comparison of the prefix.
- if (!descriptor.startsWith(sourceDescriptor)) {
- continue;
- }
- // This type should be mapped.
- if (typeMappings.containsKey(clazz.type)) {
- appView.options().reporter.error(RelocatorDiagnostic.typeRelocateAmbiguous(clazz.type));
- appView.options().reporter.failIfPendingErrors();
- }
- DexString relocatedDescriptor =
- clazz.type.descriptor.withNewPrefix(
- sourceDescriptor, targetDescriptor, appView.dexItemFactory());
- typeMappings.put(clazz.type, relocatedDescriptor);
- }
+ // TODO(b/129925954): Change to a lazy implementation in the naming lens.
+ appView
+ .dexItemFactory()
+ .forAllTypes(
+ type -> {
+ DexString descriptor = type.descriptor;
+ // Check if descriptor can be a prefix.
+ if (descriptor.size <= sourceDescriptor.size) {
+ return;
+ }
+ // Check if it is either the empty prefix or a fully qualified package.
+ if (sourceDescriptor.size != 1
+ && descriptor.content[sourceDescriptor.size]
+ != DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR) {
+ return;
+ }
+ // Do a char-by-char comparison of the prefix.
+ if (!descriptor.startsWith(sourceDescriptor)) {
+ return;
+ }
+ // This type should be mapped.
+ if (typeMappings.containsKey(type)) {
+ appView.options().reporter.error(RelocatorDiagnostic.typeRelocateAmbiguous(type));
+ appView.options().reporter.failIfPendingErrors();
+ }
+ DexString relocatedDescriptor =
+ type.descriptor.withNewPrefix(
+ sourceDescriptor, targetDescriptor, appView.dexItemFactory());
+ typeMappings.put(type, relocatedDescriptor);
+ });
}
return new RelocatorNamingLens(typeMappings, packingMappings.build(), appView.dexItemFactory());
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 3f657b9..77edcc6 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexEncodedMethod.asProgramMethodOrNull;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.GraphLense.rewriteReferenceKeys;
import static com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult.isOverriding;
@@ -34,6 +35,7 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl;
import com.android.tools.r8.graph.PresortedComparable;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -1074,6 +1076,15 @@
}
}
+ public ProgramMethod lookupSingleProgramTarget(
+ Type type,
+ DexMethod target,
+ DexType invocationContext,
+ LibraryModeledPredicate modeledPredicate) {
+ return asProgramMethodOrNull(
+ lookupSingleTarget(type, target, invocationContext, modeledPredicate), this);
+ }
+
/** For mapping invoke virtual instruction to single target method. */
public DexEncodedMethod lookupSingleVirtualTarget(
DexMethod method, DexType invocationContext, boolean isInterface) {
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index 09aafdb..7c0afe9 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -20,10 +20,9 @@
private final ProgramMethod context;
protected final Enqueuer enqueuer;
- public DefaultEnqueuerUseRegistry(
- AppView<?> appView, DexProgramClass holder, DexEncodedMethod method, Enqueuer enqueuer) {
+ public DefaultEnqueuerUseRegistry(AppView<?> appView, ProgramMethod context, Enqueuer enqueuer) {
super(appView.dexItemFactory());
- this.context = new ProgramMethod(holder, method);
+ this.context = context;
this.enqueuer = enqueuer;
}
@@ -71,22 +70,22 @@
@Override
public boolean registerInstanceFieldRead(DexField field) {
- return enqueuer.traceInstanceFieldRead(field, context.getDefinition());
+ return enqueuer.traceInstanceFieldRead(field, context);
}
@Override
public boolean registerInstanceFieldReadFromMethodHandle(DexField field) {
- return enqueuer.traceInstanceFieldReadFromMethodHandle(field, context.getDefinition());
+ return enqueuer.traceInstanceFieldReadFromMethodHandle(field, context);
}
@Override
public boolean registerInstanceFieldWrite(DexField field) {
- return enqueuer.traceInstanceFieldWrite(field, context.getDefinition());
+ return enqueuer.traceInstanceFieldWrite(field, context);
}
@Override
public boolean registerInstanceFieldWriteFromMethodHandle(DexField field) {
- return enqueuer.traceInstanceFieldWriteFromMethodHandle(field, context.getDefinition());
+ return enqueuer.traceInstanceFieldWriteFromMethodHandle(field, context);
}
@Override
@@ -96,43 +95,43 @@
@Override
public boolean registerStaticFieldRead(DexField field) {
- return enqueuer.traceStaticFieldRead(field, context.getDefinition());
+ return enqueuer.traceStaticFieldRead(field, context);
}
@Override
public boolean registerStaticFieldReadFromMethodHandle(DexField field) {
- return enqueuer.traceStaticFieldReadFromMethodHandle(field, context.getDefinition());
+ return enqueuer.traceStaticFieldReadFromMethodHandle(field, context);
}
@Override
public boolean registerStaticFieldWrite(DexField field) {
- return enqueuer.traceStaticFieldWrite(field, context.getDefinition());
+ return enqueuer.traceStaticFieldWrite(field, context);
}
@Override
public boolean registerStaticFieldWriteFromMethodHandle(DexField field) {
- return enqueuer.traceStaticFieldWriteFromMethodHandle(field, context.getDefinition());
+ return enqueuer.traceStaticFieldWriteFromMethodHandle(field, context);
}
@Override
public boolean registerConstClass(DexType type) {
- return enqueuer.traceConstClass(type, context.getDefinition());
+ return enqueuer.traceConstClass(type, context);
}
@Override
public boolean registerCheckCast(DexType type) {
- return enqueuer.traceCheckCast(type, context.getDefinition());
+ return enqueuer.traceCheckCast(type, context);
}
@Override
public boolean registerTypeReference(DexType type) {
- return enqueuer.traceTypeReference(type, context.getDefinition());
+ return enqueuer.traceTypeReference(type, context);
}
@Override
public void registerMethodHandle(DexMethodHandle methodHandle, MethodHandleUse use) {
super.registerMethodHandle(methodHandle, use);
- enqueuer.traceMethodHandle(methodHandle, use, context.getDefinition());
+ enqueuer.traceMethodHandle(methodHandle, use, context);
}
@Override
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 a1d6312..9604389 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -85,7 +85,6 @@
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
@@ -104,6 +103,7 @@
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Visibility;
import com.android.tools.r8.utils.WorkList;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
@@ -201,8 +201,8 @@
* Tracks the dependency between a method and the super-method it calls, if any. Used to make
* super methods become live when they become reachable from a live sub-method.
*/
- private final Map<DexEncodedMethod, Set<DexEncodedMethod>> superInvokeDependencies = Maps
- .newIdentityHashMap();
+ private final Map<DexEncodedMethod, ProgramMethodSet> superInvokeDependencies =
+ Maps.newIdentityHashMap();
/** Set of instance fields that can be reached by read/write operations. */
private final Map<DexProgramClass, SetWithReason<DexEncodedField>> reachableInstanceFields =
Maps.newIdentityHashMap();
@@ -283,10 +283,8 @@
/** A queue of items that need processing. Different items trigger different actions. */
private final EnqueuerWorklist workList;
- /**
- * A set of methods that need code inspection for Java reflection in use.
- */
- private final Set<DexEncodedMethod> pendingReflectiveUses = Sets.newLinkedHashSet();
+ /** A set of methods that need code inspection for Java reflection in use. */
+ private final ProgramMethodSet pendingReflectiveUses = ProgramMethodSet.createLinked();
/** Mapping of types to the methods reachable at that type. */
private final Map<DexProgramClass, Set<DexMethod>> reachableVirtualTargets =
@@ -336,7 +334,7 @@
private final LambdaRewriter lambdaRewriter;
private final DesugaredLibraryConversionWrapperAnalysis desugaredLibraryWrapperAnalysis;
- private final Map<DexType, Pair<LambdaClass, DexEncodedMethod>> lambdaClasses =
+ private final Map<DexType, Pair<LambdaClass, ProgramMethod>> lambdaClasses =
new IdentityHashMap<>();
private final Map<DexEncodedMethod, Map<DexCallSite, LambdaClass>> lambdaCallSites =
new IdentityHashMap<>();
@@ -600,15 +598,14 @@
} else {
workList.enqueueMarkInstantiatedAction(clazz, null, InstantiationReason.KEEP_RULE, witness);
if (clazz.hasDefaultInitializer()) {
- DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer();
+ ProgramMethod defaultInitializer = clazz.getProgramDefaultInitializer();
if (forceProguardCompatibility) {
workList.enqueueMarkMethodKeptAction(
- clazz,
defaultInitializer,
- graphReporter.reportCompatKeepDefaultInitializer(clazz, defaultInitializer));
+ graphReporter.reportCompatKeepDefaultInitializer(defaultInitializer));
}
if (clazz.isExternalizable(appView)) {
- enqueueMarkMethodLiveAction(clazz, defaultInitializer, witness);
+ enqueueMarkMethodLiveAction(defaultInitializer, witness);
}
}
}
@@ -626,8 +623,7 @@
DexProgramClass holder = getProgramClassOrNull(encodedMethod.holder());
if (holder != null) {
workList.enqueueMarkMethodKeptAction(
- holder,
- encodedMethod,
+ new ProgramMethod(holder, encodedMethod),
graphReporter.reportKeepMethod(precondition, rules, encodedMethod));
}
} else {
@@ -649,16 +645,14 @@
clazz = superClass;
}
if (clazz.hasDefaultInitializer()) {
- enqueueMarkMethodLiveAction(clazz, clazz.getDefaultInitializer(), reason);
+ enqueueMarkMethodLiveAction(clazz.getProgramDefaultInitializer(), reason);
}
}
// Utility to avoid adding to the worklist if already live.
- private boolean enqueueMarkMethodLiveAction(
- DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
- assert method.holder() == clazz.type;
- if (liveMethods.add(clazz, method, reason)) {
- workList.enqueueMarkMethodLiveAction(clazz, method, reason);
+ private boolean enqueueMarkMethodLiveAction(ProgramMethod method, KeepReason reason) {
+ if (liveMethods.add(method, reason)) {
+ workList.enqueueMarkMethodLiveAction(method, reason);
return true;
}
return false;
@@ -678,34 +672,39 @@
//
private boolean registerMethodWithTargetAndContext(
- Map<DexMethod, Set<DexEncodedMethod>> seen, DexMethod method, DexEncodedMethod context) {
+ Map<DexMethod, Set<DexEncodedMethod>> seen, DexMethod method, ProgramMethod context) {
DexType baseHolder = method.holder.toBaseType(appView.dexItemFactory());
if (baseHolder.isClassType()) {
markTypeAsLive(baseHolder, clazz -> graphReporter.reportClassReferencedFrom(clazz, context));
- return seen.computeIfAbsent(method, ignore -> Sets.newIdentityHashSet()).add(context);
+ return seen.computeIfAbsent(method, ignore -> Sets.newIdentityHashSet())
+ .add(context.getDefinition());
}
return false;
}
- public boolean registerFieldRead(DexField field, DexEncodedMethod context) {
- return registerFieldAccess(field, context, true, false);
+ public boolean registerFieldRead(DexField field, ProgramMethod context) {
+ return registerFieldAccess(field, context.getDefinition(), true, false);
}
- public boolean registerReflectiveFieldRead(DexField field, DexEncodedMethod context) {
- return registerFieldAccess(field, context, true, true);
+ public boolean registerFieldReadFromAnnotation(DexField field) {
+ return registerFieldAccess(field, DexEncodedMethod.ANNOTATION_REFERENCE, true, false);
}
- public boolean registerFieldWrite(DexField field, DexEncodedMethod context) {
- return registerFieldAccess(field, context, false, false);
+ public boolean registerReflectiveFieldRead(DexField field, ProgramMethod context) {
+ return registerFieldAccess(field, context.getDefinition(), true, true);
}
- public boolean registerReflectiveFieldWrite(DexField field, DexEncodedMethod context) {
- return registerFieldAccess(field, context, false, true);
+ public boolean registerFieldWrite(DexField field, ProgramMethod context) {
+ return registerFieldAccess(field, context.getDefinition(), false, false);
}
- public boolean registerReflectiveFieldAccess(DexField field, DexEncodedMethod context) {
- boolean changed = registerFieldAccess(field, context, true, true);
- changed |= registerFieldAccess(field, context, false, true);
+ public boolean registerReflectiveFieldWrite(DexField field, ProgramMethod context) {
+ return registerFieldAccess(field, context.getDefinition(), false, true);
+ }
+
+ public boolean registerReflectiveFieldAccess(DexField field, ProgramMethod context) {
+ boolean changed = registerFieldAccess(field, context.getDefinition(), true, true);
+ changed |= registerFieldAccess(field, context.getDefinition(), false, true);
return changed;
}
@@ -745,12 +744,6 @@
return isRead ? info.recordRead(field, context) : info.recordWrite(field, context);
}
- private boolean isStringConcat(DexMethodHandle bootstrapMethod) {
- return bootstrapMethod.type.isInvokeStatic()
- && (bootstrapMethod.asMethod() == appView.dexItemFactory().stringConcatWithConstantsMethod
- || bootstrapMethod.asMethod() == appView.dexItemFactory().stringConcatMethod);
- }
-
void traceCallSite(DexCallSite callSite, ProgramMethod context) {
DexProgramClass bootstrapClass =
getProgramClassOrNull(callSite.bootstrapMethod.asMethod().holder);
@@ -771,7 +764,7 @@
if (code != null) {
LambdaClass lambdaClass =
lambdaRewriter.getOrCreateLambdaClass(descriptor, contextMethod.holder());
- lambdaClasses.put(lambdaClass.type, new Pair<>(lambdaClass, contextMethod));
+ lambdaClasses.put(lambdaClass.type, new Pair<>(lambdaClass, context));
lambdaCallSites
.computeIfAbsent(contextMethod, k -> new IdentityHashMap<>())
.put(callSite, lambdaClass);
@@ -783,7 +776,7 @@
desugaredLambdaImplementationMethods.add(descriptor.implHandle.asMethod());
}
} else {
- markLambdaAsInstantiated(descriptor, contextMethod);
+ markLambdaAsInstantiated(descriptor, context);
transitionMethodsForInstantiatedLambda(descriptor);
callSites.add(callSite);
}
@@ -820,11 +813,11 @@
}
}
- boolean traceCheckCast(DexType type, DexEncodedMethod currentMethod) {
+ boolean traceCheckCast(DexType type, ProgramMethod currentMethod) {
return traceConstClassOrCheckCast(type, currentMethod);
}
- boolean traceConstClass(DexType type, DexEncodedMethod currentMethod) {
+ boolean traceConstClass(DexType type, ProgramMethod currentMethod) {
// We conservatively group T.class and T[].class to ensure that we do not merge T with S if
// potential locks on T[].class and S[].class exists.
DexType baseType = type.toBaseType(appView.dexItemFactory());
@@ -837,7 +830,7 @@
return traceConstClassOrCheckCast(type, currentMethod);
}
- private boolean traceConstClassOrCheckCast(DexType type, DexEncodedMethod currentMethod) {
+ private boolean traceConstClassOrCheckCast(DexType type, ProgramMethod currentMethod) {
if (!forceProguardCompatibility) {
return traceTypeReference(type, currentMethod);
}
@@ -868,7 +861,7 @@
initClassReferences.put(
type, computeMinimumRequiredVisibilityForInitClassField(type, currentMethod.getHolder()));
- markTypeAsLive(type, classReferencedFromReporter(currentMethod.getDefinition()));
+ markTypeAsLive(type, classReferencedFromReporter(currentMethod));
markDirectAndIndirectClassInitializersAsLive(clazz);
return true;
}
@@ -914,7 +907,7 @@
}
void traceMethodHandle(
- DexMethodHandle methodHandle, MethodHandleUse use, DexEncodedMethod currentMethod) {
+ DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod currentMethod) {
// If a method handle is not an argument to a lambda metafactory it could flow to a
// MethodHandle.invokeExact invocation. For that to work, the receiver type cannot have
// changed and therefore we cannot perform member rebinding. For these handles, we maintain
@@ -938,33 +931,28 @@
}
}
- boolean traceTypeReference(DexType type, DexEncodedMethod currentMethod) {
+ boolean traceTypeReference(DexType type, ProgramMethod currentMethod) {
markTypeAsLive(type, classReferencedFromReporter(currentMethod));
return true;
}
boolean traceInvokeDirect(DexMethod invokedMethod, ProgramMethod context) {
- DexProgramClass currentHolder = context.getHolder();
- DexEncodedMethod currentMethod = context.getDefinition();
boolean skipTracing =
registerDeferredActionForDeadProtoBuilder(
invokedMethod.holder,
- currentMethod,
- () ->
- workList.enqueueTraceInvokeDirectAction(
- invokedMethod, currentHolder, currentMethod));
+ context,
+ () -> workList.enqueueTraceInvokeDirectAction(invokedMethod, context));
if (skipTracing) {
addDeadProtoTypeCandidate(invokedMethod.holder);
return false;
}
- return traceInvokeDirect(
- invokedMethod, context, KeepReason.invokedFrom(currentHolder, currentMethod));
+ return traceInvokeDirect(invokedMethod, context, KeepReason.invokedFrom(context));
}
/** Returns true if a deferred action was registered. */
private boolean registerDeferredActionForDeadProtoBuilder(
- DexType type, DexEncodedMethod currentMethod, Action action) {
+ DexType type, ProgramMethod currentMethod, Action action) {
DexProgramClass clazz = getProgramClassOrNull(type);
if (clazz != null) {
return appView.withGeneratedMessageLiteBuilderShrinker(
@@ -978,13 +966,12 @@
boolean traceInvokeDirectFromLambda(DexMethod invokedMethod, ProgramMethod context) {
return traceInvokeDirect(
- invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context.getDefinition()));
+ invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context));
}
private boolean traceInvokeDirect(
DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
- DexEncodedMethod currentMethod = context.getDefinition();
- if (!registerMethodWithTargetAndContext(directInvokes, invokedMethod, currentMethod)) {
+ if (!registerMethodWithTargetAndContext(directInvokes, invokedMethod, context)) {
return false;
}
if (Log.ENABLED) {
@@ -1001,13 +988,12 @@
boolean traceInvokeInterfaceFromLambda(DexMethod invokedMethod, ProgramMethod context) {
return traceInvokeInterface(
- invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context.getDefinition()));
+ invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context));
}
private boolean traceInvokeInterface(
DexMethod method, ProgramMethod context, KeepReason keepReason) {
- DexEncodedMethod currentMethod = context.getDefinition();
- if (!registerMethodWithTargetAndContext(interfaceInvokes, method, currentMethod)) {
+ if (!registerMethodWithTargetAndContext(interfaceInvokes, method, context)) {
return false;
}
if (Log.ENABLED) {
@@ -1024,32 +1010,31 @@
boolean traceInvokeStaticFromLambda(DexMethod invokedMethod, ProgramMethod context) {
return traceInvokeStatic(
- invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context.getDefinition()));
+ invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context));
}
private boolean traceInvokeStatic(
DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
- DexEncodedMethod currentMethod = context.getDefinition();
DexItemFactory dexItemFactory = appView.dexItemFactory();
if (dexItemFactory.classMethods.isReflectiveClassLookup(invokedMethod)
|| dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod)) {
// Implicitly add -identifiernamestring rule for the Java reflection in use.
identifierNameStrings.add(invokedMethod);
// Revisit the current method to implicitly add -keep rule for items with reflective access.
- pendingReflectiveUses.add(currentMethod);
+ pendingReflectiveUses.add(context);
}
// See comment in handleJavaLangEnumValueOf.
if (invokedMethod == dexItemFactory.enumMethods.valueOf) {
- pendingReflectiveUses.add(currentMethod);
+ pendingReflectiveUses.add(context);
}
// Handling of application services.
if (dexItemFactory.serviceLoaderMethods.isLoadMethod(invokedMethod)) {
- pendingReflectiveUses.add(currentMethod);
+ pendingReflectiveUses.add(context);
}
if (invokedMethod == dexItemFactory.proxyMethods.newProxyInstance) {
- pendingReflectiveUses.add(currentMethod);
+ pendingReflectiveUses.add(context);
}
- if (!registerMethodWithTargetAndContext(staticInvokes, invokedMethod, currentMethod)) {
+ if (!registerMethodWithTargetAndContext(staticInvokes, invokedMethod, context)) {
return false;
}
if (Log.ENABLED) {
@@ -1061,17 +1046,16 @@
}
boolean traceInvokeSuper(DexMethod invokedMethod, ProgramMethod context) {
- DexEncodedMethod currentMethod = context.getDefinition();
// We have to revisit super invokes based on the context they are found in. The same
// method descriptor will hit different targets, depending on the context it is used in.
- DexMethod actualTarget = getInvokeSuperTarget(invokedMethod, currentMethod);
- if (!registerMethodWithTargetAndContext(superInvokes, invokedMethod, currentMethod)) {
+ DexMethod actualTarget = getInvokeSuperTarget(invokedMethod, context);
+ if (!registerMethodWithTargetAndContext(superInvokes, invokedMethod, context)) {
return false;
}
if (Log.ENABLED) {
Log.verbose(getClass(), "Register invokeSuper `%s`.", actualTarget);
}
- workList.enqueueMarkReachableSuperAction(invokedMethod, currentMethod);
+ workList.enqueueMarkReachableSuperAction(invokedMethod, context);
invokeAnalyses.forEach(analysis -> analysis.traceInvokeSuper(invokedMethod, context));
return true;
}
@@ -1082,22 +1066,21 @@
boolean traceInvokeVirtualFromLambda(DexMethod invokedMethod, ProgramMethod context) {
return traceInvokeVirtual(
- invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context.getDefinition()));
+ invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context));
}
private boolean traceInvokeVirtual(
DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
if (invokedMethod == appView.dexItemFactory().classMethods.newInstance
|| invokedMethod == appView.dexItemFactory().constructorMethods.newInstance) {
- pendingReflectiveUses.add(context.getDefinition());
+ pendingReflectiveUses.add(context);
} else if (appView.dexItemFactory().classMethods.isReflectiveMemberLookup(invokedMethod)) {
// Implicitly add -identifiernamestring rule for the Java reflection in use.
identifierNameStrings.add(invokedMethod);
// Revisit the current method to implicitly add -keep rule for items with reflective access.
- pendingReflectiveUses.add(context.getDefinition());
+ pendingReflectiveUses.add(context);
}
- if (!registerMethodWithTargetAndContext(
- virtualInvokes, invokedMethod, context.getDefinition())) {
+ if (!registerMethodWithTargetAndContext(virtualInvokes, invokedMethod, context)) {
return false;
}
if (Log.ENABLED) {
@@ -1109,10 +1092,9 @@
}
boolean traceNewInstance(DexType type, ProgramMethod context) {
- DexEncodedMethod currentMethod = context.getDefinition();
boolean skipTracing =
registerDeferredActionForDeadProtoBuilder(
- type, currentMethod, () -> workList.enqueueTraceNewInstanceAction(type, context));
+ type, context, () -> workList.enqueueTraceNewInstanceAction(type, context));
if (skipTracing) {
addDeadProtoTypeCandidate(type);
return false;
@@ -1122,15 +1104,12 @@
type,
context,
InstantiationReason.NEW_INSTANCE_INSTRUCTION,
- KeepReason.instantiatedIn(currentMethod));
+ KeepReason.instantiatedIn(context));
}
boolean traceNewInstanceFromLambda(DexType type, ProgramMethod context) {
return traceNewInstance(
- type,
- context,
- InstantiationReason.LAMBDA,
- KeepReason.invokedFromLambdaCreatedIn(context.getDefinition()));
+ type, context, InstantiationReason.LAMBDA, KeepReason.invokedFromLambdaCreatedIn(context));
}
private boolean traceNewInstance(
@@ -1138,29 +1117,27 @@
ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason) {
- DexEncodedMethod currentMethod = context.getDefinition();
DexProgramClass clazz = getProgramClassOrNull(type);
if (clazz != null) {
if (clazz.isAnnotation() || clazz.isInterface()) {
markTypeAsLive(clazz, graphReporter.registerClass(clazz, keepReason));
} else {
- workList.enqueueMarkInstantiatedAction(
- clazz, currentMethod, instantiationReason, keepReason);
+ workList.enqueueMarkInstantiatedAction(clazz, context, instantiationReason, keepReason);
}
}
return true;
}
- boolean traceInstanceFieldRead(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceInstanceFieldRead(DexField field, ProgramMethod currentMethod) {
return traceInstanceFieldRead(field, currentMethod, false);
}
- boolean traceInstanceFieldReadFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceInstanceFieldReadFromMethodHandle(DexField field, ProgramMethod currentMethod) {
return traceInstanceFieldRead(field, currentMethod, true);
}
private boolean traceInstanceFieldRead(
- DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
+ DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldRead(field, currentMethod)) {
return false;
}
@@ -1200,16 +1177,16 @@
return true;
}
- boolean traceInstanceFieldWrite(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceInstanceFieldWrite(DexField field, ProgramMethod currentMethod) {
return traceInstanceFieldWrite(field, currentMethod, false);
}
- boolean traceInstanceFieldWriteFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceInstanceFieldWriteFromMethodHandle(DexField field, ProgramMethod currentMethod) {
return traceInstanceFieldWrite(field, currentMethod, true);
}
private boolean traceInstanceFieldWrite(
- DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
+ DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldWrite(field, currentMethod)) {
return false;
}
@@ -1249,16 +1226,16 @@
return true;
}
- boolean traceStaticFieldRead(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceStaticFieldRead(DexField field, ProgramMethod currentMethod) {
return traceStaticFieldRead(field, currentMethod, false);
}
- boolean traceStaticFieldReadFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceStaticFieldReadFromMethodHandle(DexField field, ProgramMethod currentMethod) {
return traceStaticFieldRead(field, currentMethod, true);
}
private boolean traceStaticFieldRead(
- DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
+ DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldRead(field, currentMethod)) {
return false;
}
@@ -1308,16 +1285,16 @@
return true;
}
- boolean traceStaticFieldWrite(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceStaticFieldWrite(DexField field, ProgramMethod currentMethod) {
return traceStaticFieldWrite(field, currentMethod, false);
}
- boolean traceStaticFieldWriteFromMethodHandle(DexField field, DexEncodedMethod currentMethod) {
+ boolean traceStaticFieldWriteFromMethodHandle(DexField field, ProgramMethod currentMethod) {
return traceStaticFieldWrite(field, currentMethod, true);
}
private boolean traceStaticFieldWrite(
- DexField field, DexEncodedMethod currentMethod, boolean fromMethodHandle) {
+ DexField field, ProgramMethod currentMethod, boolean fromMethodHandle) {
if (!registerFieldWrite(field, currentMethod)) {
return false;
}
@@ -1368,17 +1345,17 @@
}
private Function<DexProgramClass, KeepReasonWitness> classReferencedFromReporter(
- DexEncodedMethod currentMethod) {
+ ProgramMethod currentMethod) {
return clazz -> graphReporter.reportClassReferencedFrom(clazz, currentMethod);
}
- private DexMethod getInvokeSuperTarget(DexMethod method, DexEncodedMethod currentMethod) {
+ private DexMethod getInvokeSuperTarget(DexMethod method, ProgramMethod currentMethod) {
DexClass methodHolderClass = appView.definitionFor(method.holder);
if (methodHolderClass != null && methodHolderClass.isInterface()) {
return method;
}
- DexClass holderClass = appView.definitionFor(currentMethod.holder());
- if (holderClass == null || holderClass.superType == null || holderClass.isInterface()) {
+ DexProgramClass holderClass = currentMethod.getHolder();
+ if (holderClass.superType == null || holderClass.isInterface()) {
// We do not know better or this call is made from an interface.
return method;
}
@@ -1390,9 +1367,10 @@
// Actual actions performed.
//
- private boolean verifyMethodIsTargeted(DexEncodedMethod method) {
- assert !method.isClassInitializer() : "Class initializers are never targeted";
- assert targetedMethods.contains(method);
+ private boolean verifyMethodIsTargeted(ProgramMethod method) {
+ DexEncodedMethod definition = method.getDefinition();
+ assert !definition.isClassInitializer() : "Class initializers are never targeted";
+ assert targetedMethods.contains(definition);
return true;
}
@@ -1539,13 +1517,12 @@
private void ensureMethodsContinueToWidenAccess(
DexProgramClass clazz, ScopedDexMethodSet seen, KeepReason reason) {
- for (DexEncodedMethod method : clazz.virtualMethods()) {
- if (seen.addMethodIfMoreVisible(method) == AddMethodIfMoreVisibleResult.ADDED_MORE_VISIBLE
- && clazz.isProgramClass()
- && appView.appInfo().methodDefinedInInterfaces(method, clazz.type)) {
- markMethodAsTargeted(clazz, method, reason);
- }
- }
+ clazz.forEachProgramVirtualMethodMatching(
+ definition ->
+ seen.addMethodIfMoreVisible(definition)
+ == AddMethodIfMoreVisibleResult.ADDED_MORE_VISIBLE
+ && appView.appInfo().methodDefinedInInterfaces(definition, clazz.type),
+ method -> markMethodAsTargeted(method, reason));
}
private void markInterfaceTypeAsLiveViaInheritanceClause(
@@ -1595,9 +1572,7 @@
}
private void enqueueHolderWithDependentInstanceConstructor(
- DexProgramClass clazz,
- DexEncodedMethod instanceInitializer,
- Set<ProguardKeepRuleBase> reasons) {
+ DexProgramClass clazz, ProgramMethod instanceInitializer, Set<ProguardKeepRuleBase> reasons) {
enqueueRootItem(clazz, reasons);
}
@@ -1677,8 +1652,8 @@
return resolutionResult.asSingleResolution();
}
- private void handleInvokeOfStaticTarget(DexMethod method, KeepReason reason) {
- SingleResolutionResult resolution = resolveMethod(method, reason);
+ private void handleInvokeOfStaticTarget(DexMethod reference, KeepReason reason) {
+ SingleResolutionResult resolution = resolveMethod(reference, reason);
if (resolution == null || resolution.getResolvedHolder().isNotProgramClass()) {
return;
}
@@ -1687,12 +1662,13 @@
// We have to mark the resolved method as targeted even if it cannot actually be invoked
// to make sure the invocation will keep failing in the appropriate way.
- markMethodAsTargeted(clazz, encodedMethod, reason);
+ ProgramMethod method = new ProgramMethod(clazz, encodedMethod);
+ markMethodAsTargeted(method, reason);
// Only mark methods for which invocation will succeed at runtime live.
if (encodedMethod.isStatic()) {
markDirectAndIndirectClassInitializersAsLive(clazz);
- markDirectStaticOrConstructorMethodAsLive(clazz, encodedMethod, reason);
+ markDirectStaticOrConstructorMethodAsLive(method, reason);
}
}
@@ -1719,13 +1695,13 @@
/** Returns true if the class initializer became live for the first time. */
private boolean markDirectClassInitializerAsLive(DexProgramClass clazz) {
- DexEncodedMethod clinit = clazz.getClassInitializer();
+ ProgramMethod clinit = clazz.getProgramClassInitializer();
KeepReasonWitness witness = graphReporter.reportReachableClassInitializer(clazz, clinit);
if (!initializedTypes.add(clazz, witness)) {
return false;
}
- if (clinit != null && clinit.getOptimizationInfo().mayHaveSideEffects()) {
- markDirectStaticOrConstructorMethodAsLive(clazz, clinit, witness);
+ if (clinit != null && clinit.getDefinition().getOptimizationInfo().mayHaveSideEffects()) {
+ markDirectStaticOrConstructorMethodAsLive(clinit, witness);
}
return true;
}
@@ -1735,37 +1711,39 @@
handleInvokeOfDirectTarget(method, reason);
}
- private void handleInvokeOfDirectTarget(DexMethod method, KeepReason reason) {
- DexType holder = method.holder;
+ private void handleInvokeOfDirectTarget(DexMethod reference, KeepReason reason) {
+ DexType holder = reference.holder;
DexProgramClass clazz = getProgramClassOrNull(holder);
if (clazz == null) {
- recordMethodReference(method);
+ recordMethodReference(reference);
return;
}
// TODO(zerny): Is it ok that we lookup in both the direct and virtual pool here?
- DexEncodedMethod encodedMethod = clazz.lookupMethod(method);
+ DexEncodedMethod encodedMethod = clazz.lookupMethod(reference);
if (encodedMethod == null) {
- reportMissingMethod(method);
+ reportMissingMethod(reference);
return;
}
+ ProgramMethod method = new ProgramMethod(clazz, encodedMethod);
+
// We have to mark the resolved method as targeted even if it cannot actually be invoked
// to make sure the invocation will keep failing in the appropriate way.
- markMethodAsTargeted(clazz, encodedMethod, reason);
+ markMethodAsTargeted(method, reason);
// Only mark methods for which invocation will succeed at runtime live.
if (encodedMethod.isStatic()) {
return;
}
- markDirectStaticOrConstructorMethodAsLive(clazz, encodedMethod, reason);
+ markDirectStaticOrConstructorMethodAsLive(method, reason);
// It is valid to have an invoke-direct instruction in a default interface method that
// targets another default method in the same interface (see testInvokeSpecialToDefault-
// Method). In a class, that would lead to a verification error.
if (encodedMethod.isNonPrivateVirtualMethod()
&& virtualMethodsTargetedByInvokeDirect.add(encodedMethod.method)) {
- enqueueMarkMethodLiveAction(clazz, encodedMethod, reason);
+ enqueueMarkMethodLiveAction(method, reason);
}
}
@@ -1839,26 +1817,26 @@
}
}
- private void markMethodAsTargeted(
- DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
- assert method.holder() == clazz.type;
- if (!targetedMethods.add(method, reason)) {
+ private void markMethodAsTargeted(ProgramMethod method, KeepReason reason) {
+ DexEncodedMethod definition = method.getDefinition();
+ DexProgramClass holder = method.getHolder();
+ if (!targetedMethods.add(definition, reason)) {
// Already targeted.
return;
}
markReferencedTypesAsLive(method);
- processAnnotations(clazz, method);
- method.parameterAnnotationsList.forEachAnnotation(
- annotation -> processAnnotation(clazz, method, annotation));
+ processAnnotations(holder, definition);
+ definition.parameterAnnotationsList.forEachAnnotation(
+ annotation -> processAnnotation(holder, definition, annotation));
if (Log.ENABLED) {
- Log.verbose(getClass(), "Method `%s` is targeted.", method.method);
+ Log.verbose(getClass(), "Method `%s` is targeted.", method);
}
if (forceProguardCompatibility) {
// Keep targeted default methods in compatibility mode. The tree pruner will otherwise make
// these methods abstract, whereas Proguard does not (seem to) touch their code.
- if (!method.accessFlags.isAbstract() && clazz.isInterface()) {
- markMethodAsLiveWithCompatRule(clazz, method);
+ if (!definition.isAbstract() && holder.isInterface()) {
+ markMethodAsLiveWithCompatRule(method);
}
}
}
@@ -1870,7 +1848,7 @@
// Package protected due to entry point from worklist.
void processNewlyInstantiatedClass(
DexProgramClass clazz,
- DexEncodedMethod context,
+ ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason) {
assert !clazz.isAnnotation();
@@ -1905,7 +1883,7 @@
// TODO(b/146016987): Make this the single instantiation entry rather than the worklist action.
private boolean markInstantiatedClass(
DexProgramClass clazz,
- DexEncodedMethod context,
+ ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason) {
assert !clazz.isInterface();
@@ -1923,7 +1901,7 @@
transitionDependentItemsForInstantiatedInterface(clazz);
}
- private void markLambdaAsInstantiated(LambdaDescriptor descriptor, DexEncodedMethod context) {
+ private void markLambdaAsInstantiated(LambdaDescriptor descriptor, ProgramMethod context) {
// Each descriptor is unique, so there is no check for already marking the lambda.
for (DexType iface : descriptor.interfaces) {
checkLambdaInterface(iface, context);
@@ -1931,13 +1909,13 @@
}
}
- private void checkLambdaInterface(DexType itf, DexEncodedMethod context) {
+ private void checkLambdaInterface(DexType itf, ProgramMethod context) {
DexClass clazz = definitionFor(itf);
if (clazz == null) {
StringDiagnostic message =
new StringDiagnostic(
"Lambda expression implements missing interface `" + itf.toSourceString() + "`",
- appInfo.originFor(context.holder()));
+ context.getOrigin());
options.reporter.warning(message);
} else if (!clazz.isInterface()) {
StringDiagnostic message =
@@ -1946,7 +1924,7 @@
+ "`"
+ itf.toSourceString()
+ "`",
- appInfo.originFor(context.holder()));
+ context.getOrigin());
options.reporter.warning(message);
}
}
@@ -2040,8 +2018,7 @@
// simply marked live on its holder.
if (resolutionMethod.getDefinition().isPrivateMethod()) {
markVirtualMethodAsLive(
- resolutionMethod.getHolder(),
- resolutionMethod.getDefinition(),
+ resolutionMethod,
graphReporter.reportReachableMethodAsLive(
resolutionMethod.getDefinition().method, resolutionMethod));
return;
@@ -2194,7 +2171,7 @@
}
}
- private void markFieldAsTargeted(DexField field, DexEncodedMethod context) {
+ private void markFieldAsTargeted(DexField field, ProgramMethod context) {
markTypeAsLive(field.type, clazz -> graphReporter.reportClassReferencedFrom(clazz, context));
markTypeAsLive(field.holder, clazz -> graphReporter.reportClassReferencedFrom(clazz, context));
}
@@ -2256,34 +2233,28 @@
analyses.forEach(analysis -> analysis.processNewlyLiveField(field));
}
- private void markDirectStaticOrConstructorMethodAsLive(
- DexProgramClass clazz, DexEncodedMethod encodedMethod, KeepReason reason) {
- assert encodedMethod.holder() == clazz.type;
-
- if (!enqueueMarkMethodLiveAction(clazz, encodedMethod, reason)) {
+ private void markDirectStaticOrConstructorMethodAsLive(ProgramMethod method, KeepReason reason) {
+ if (!enqueueMarkMethodLiveAction(method, reason)) {
// Already marked live.
return;
}
// Should already have marked the type live previously.
- DexMethod method = encodedMethod.method;
- assert encodedMethod.isClassInitializer() || verifyMethodIsTargeted(encodedMethod);
- assert verifyTypeIsLive(clazz);
+ assert method.getDefinition().isClassInitializer() || verifyMethodIsTargeted(method);
+ assert verifyTypeIsLive(method.getHolder());
if (Log.ENABLED) {
- Log.verbose(
- getClass(), "Method `%s` has become live due to direct invoke", encodedMethod.method);
+ Log.verbose(getClass(), "Method `%s` has become live due to direct invoke", method);
}
}
- private void markVirtualMethodAsLive(
- DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
+ private void markVirtualMethodAsLive(ProgramMethod method, KeepReason reason) {
assert method != null;
// Only explicit keep rules or reflective use should make abstract methods live.
- assert !method.accessFlags.isAbstract()
+ assert !method.getDefinition().isAbstract()
|| reason.isDueToKeepRule()
|| reason.isDueToReflectiveUse();
- if (enqueueMarkMethodLiveAction(clazz, method, reason)) {
+ if (enqueueMarkMethodLiveAction(method, reason)) {
if (Log.ENABLED) {
- Log.verbose(getClass(), "Adding virtual method `%s` to live set.", method.method);
+ Log.verbose(getClass(), "Adding virtual method `%s` to live set.", method);
}
}
}
@@ -2434,7 +2405,7 @@
// need at least an abstract version of it so that it can be targeted.
DexProgramClass resolvedHolder = resolution.getResolvedHolder().asProgramClass();
DexEncodedMethod resolvedMethod = resolution.getResolvedMethod();
- markMethodAsTargeted(resolvedHolder, resolvedMethod, reason);
+ markMethodAsTargeted(new ProgramMethod(resolvedHolder, resolvedMethod), reason);
DexProgramClass context = contextOrNull == null ? null : contextOrNull.getHolder();
if (contextOrNull != null
@@ -2484,8 +2455,7 @@
DexClassAndMethod target, Function<ProgramMethod, KeepReasonWitness> reason) {
ProgramMethod programMethod = target.asProgramMethod();
if (programMethod != null && !programMethod.getDefinition().isAbstract()) {
- markVirtualMethodAsLive(
- programMethod.getHolder(), programMethod.getDefinition(), reason.apply(programMethod));
+ markVirtualMethodAsLive(programMethod, reason.apply(programMethod));
}
}
@@ -2493,10 +2463,7 @@
LookupLambdaTarget target, Function<ProgramMethod, KeepReasonWitness> reason) {
ProgramMethod implementationMethod = target.getImplementationMethod().asProgramMethod();
if (implementationMethod != null) {
- enqueueMarkMethodLiveAction(
- implementationMethod.getHolder(),
- implementationMethod.getDefinition(),
- reason.apply(implementationMethod));
+ enqueueMarkMethodLiveAction(implementationMethod, reason.apply(implementationMethod));
}
}
@@ -2508,7 +2475,7 @@
DexProgramClass clazz = getProgramClassOrNull(method.holder());
if (clazz != null) {
failedResolutionTargets.add(method.method);
- markMethodAsTargeted(clazz, method, reason);
+ markMethodAsTargeted(new ProgramMethod(clazz, method), reason);
}
});
}
@@ -2530,28 +2497,28 @@
if (valuesMethod != null) {
// TODO(sgjesse): Does this have to be enqueued as a root item? Right now it is done as the
// marking for not renaming it is in the root set.
- workList.enqueueMarkMethodKeptAction(clazz, valuesMethod, reason);
+ workList.enqueueMarkMethodKeptAction(new ProgramMethod(clazz, valuesMethod), reason);
pinnedItems.add(valuesMethod.toReference());
rootSet.shouldNotBeMinified(valuesMethod.toReference());
}
}
// Package protected due to entry point from worklist.
- void markSuperMethodAsReachable(DexMethod method, DexEncodedMethod from) {
+ void markSuperMethodAsReachable(DexMethod reference, ProgramMethod from) {
KeepReason reason = KeepReason.targetedBySuperFrom(from);
- SingleResolutionResult resolution = resolveMethod(method, reason);
+ SingleResolutionResult resolution = resolveMethod(reference, reason);
if (resolution == null) {
return;
}
// If the resolution is in the program, mark it targeted.
if (resolution.getResolvedHolder().isProgramClass()) {
markMethodAsTargeted(
- resolution.getResolvedHolder().asProgramClass(), resolution.getResolvedMethod(), reason);
+ new ProgramMethod(
+ resolution.getResolvedHolder().asProgramClass(), resolution.getResolvedMethod()),
+ reason);
}
// If invoke target is invalid (inaccessible or not an instance-method) record it and stop.
- // TODO(b/146016987): We should be passing the full program context and not looking it up again.
- DexProgramClass fromHolder = appInfo.definitionFor(from.holder()).asProgramClass();
- DexEncodedMethod target = resolution.lookupInvokeSuperTarget(fromHolder, appInfo);
+ DexEncodedMethod target = resolution.lookupInvokeSuperTarget(from.getHolder(), appInfo);
if (target == null) {
failedResolutionTargets.add(resolution.getResolvedMethod().method);
return;
@@ -2561,16 +2528,19 @@
if (clazz == null) {
return;
}
+
+ ProgramMethod method = new ProgramMethod(clazz, target);
+
if (Log.ENABLED) {
- Log.verbose(getClass(), "Adding super constraint from `%s` to `%s`", from.method,
- target.method);
+ Log.verbose(getClass(), "Adding super constraint from `%s` to `%s`", from, target.method);
}
- if (superInvokeDependencies.computeIfAbsent(
- from, ignore -> Sets.newIdentityHashSet()).add(target)) {
+ if (superInvokeDependencies
+ .computeIfAbsent(from.getDefinition(), ignore -> ProgramMethodSet.create())
+ .add(method)) {
if (liveMethods.contains(from)) {
- markMethodAsTargeted(clazz, target, KeepReason.invokedViaSuperFrom(from));
+ markMethodAsTargeted(method, KeepReason.invokedViaSuperFrom(from));
if (!target.accessFlags.isAbstract()) {
- markVirtualMethodAsLive(clazz, target, KeepReason.invokedViaSuperFrom(from));
+ markVirtualMethodAsLive(method, KeepReason.invokedViaSuperFrom(from));
}
}
}
@@ -2629,7 +2599,7 @@
private static class SyntheticAdditions {
- Map<DexType, Pair<DexProgramClass, DexEncodedMethod>> syntheticInstantiations =
+ Map<DexType, Pair<DexProgramClass, ProgramMethod>> syntheticInstantiations =
new IdentityHashMap<>();
Map<DexMethod, ProgramMethod> liveMethods = new IdentityHashMap<>();
@@ -2649,7 +2619,7 @@
}
void addInstantiatedClass(
- DexProgramClass clazz, DexEncodedMethod context, boolean isMainDexClass) {
+ DexProgramClass clazz, ProgramMethod context, boolean isMainDexClass) {
assert !syntheticInstantiations.containsKey(clazz.type);
syntheticInstantiations.put(clazz.type, new Pair<>(clazz, context));
if (isMainDexClass) {
@@ -2675,7 +2645,7 @@
void amendApplication(Builder appBuilder) {
assert !isEmpty();
- for (Pair<DexProgramClass, DexEncodedMethod> clazzAndContext :
+ for (Pair<DexProgramClass, ProgramMethod> clazzAndContext :
syntheticInstantiations.values()) {
appBuilder.addProgramClass(clazzAndContext.getFirst());
}
@@ -2690,7 +2660,7 @@
KeepReasonWitness fakeReason = enqueuer.graphReporter.fakeReportShouldNotBeUsed();
enqueuer.pinnedItems.addAll(pinnedMethods);
- for (Pair<DexProgramClass, DexEncodedMethod> clazzAndContext :
+ for (Pair<DexProgramClass, ProgramMethod> clazzAndContext :
syntheticInstantiations.values()) {
enqueuer.workList.enqueueMarkInstantiatedAction(
clazzAndContext.getFirst(),
@@ -2700,10 +2670,8 @@
}
for (ProgramMethod liveMethod : liveMethods.values()) {
assert !enqueuer.targetedMethods.contains(liveMethod.getDefinition());
- DexProgramClass holder = liveMethod.getHolder();
- DexEncodedMethod method = liveMethod.getDefinition();
- enqueuer.markMethodAsTargeted(holder, method, fakeReason);
- enqueuer.enqueueMarkMethodLiveAction(holder, method, fakeReason);
+ enqueuer.markMethodAsTargeted(liveMethod, fakeReason);
+ enqueuer.enqueueMarkMethodLiveAction(liveMethod, fakeReason);
}
}
}
@@ -2752,17 +2720,18 @@
assert classesWithSerializableLambdas.isEmpty();
return;
}
- for (Pair<LambdaClass, DexEncodedMethod> lambdaClassAndContext : lambdaClasses.values()) {
+ for (Pair<LambdaClass, ProgramMethod> lambdaClassAndContext : lambdaClasses.values()) {
// Add all desugared classes to the application, main-dex list, and mark them instantiated.
LambdaClass lambdaClass = lambdaClassAndContext.getFirst();
- DexEncodedMethod context = lambdaClassAndContext.getSecond();
+ ProgramMethod context = lambdaClassAndContext.getSecond();
DexProgramClass programClass = lambdaClass.getOrCreateLambdaClass();
additions.addInstantiatedClass(programClass, context, lambdaClass.addToMainDexList.get());
// Mark the instance constructor targeted and live.
DexEncodedMethod constructor = programClass.lookupDirectMethod(lambdaClass.constructor);
KeepReason reason = KeepReason.instantiatedIn(context);
- markMethodAsTargeted(programClass, constructor, reason);
- markDirectStaticOrConstructorMethodAsLive(programClass, constructor, reason);
+ ProgramMethod method = new ProgramMethod(programClass, constructor);
+ markMethodAsTargeted(method, reason);
+ markDirectStaticOrConstructorMethodAsLive(method, reason);
}
// Rewrite all of the invoke-dynamic instructions to lambda class instantiations.
@@ -2915,14 +2884,9 @@
if (!liveMethods.contains(synthesizedClass.lookupMethod(method))) {
return;
}
- DexEncodedMethod accessor = lambda.target.ensureAccessibilityIfNeeded(false);
- if (accessor == null) {
- return;
- }
- DexProgramClass accessorClass = getProgramClassOrNull(accessor.holder());
- assert accessorClass != null;
- if (accessorClass != null) {
- liveMethods.add(accessorClass, accessor, graphReporter.fakeReportShouldNotBeUsed());
+ ProgramMethod accessor = lambda.target.ensureAccessibilityIfNeeded(false);
+ if (accessor != null) {
+ liveMethods.add(accessor, graphReporter.fakeReportShouldNotBeUsed());
}
});
}
@@ -2995,11 +2959,8 @@
}
// Generate first the callbacks since they may require extra wrappers.
- List<DexEncodedMethod> callbacks = desugaredLibraryWrapperAnalysis.generateCallbackMethods();
- for (DexEncodedMethod callback : callbacks) {
- DexProgramClass clazz = getProgramClassOrNull(callback.holder());
- additions.addLiveMethod(new ProgramMethod(clazz, callback));
- }
+ ProgramMethodSet callbacks = desugaredLibraryWrapperAnalysis.generateCallbackMethods();
+ callbacks.forEach(additions::addLiveMethod);
// Generate the wrappers.
List<DexProgramClass> wrappers = desugaredLibraryWrapperAnalysis.generateWrappers();
@@ -3261,8 +3222,7 @@
singleTargetHolder.isInterface(),
null,
graphReporter.fakeReportShouldNotBeUsed());
- enqueueMarkMethodLiveAction(
- singleTargetHolder, singleTargetMethod, graphReporter.fakeReportShouldNotBeUsed());
+ enqueueMarkMethodLiveAction(singleTarget, graphReporter.fakeReportShouldNotBeUsed());
}
}
action.getAction().accept(builder);
@@ -3286,36 +3246,37 @@
}
// Package protected due to entry point from worklist.
- void markMethodAsKept(DexProgramClass holder, DexEncodedMethod target, KeepReason reason) {
- DexMethod method = target.method;
- if (target.isVirtualMethod()) {
+ void markMethodAsKept(ProgramMethod target, KeepReason reason) {
+ DexEncodedMethod definition = target.getDefinition();
+ DexProgramClass holder = target.getHolder();
+ DexMethod reference = target.getReference();
+ if (definition.isVirtualMethod()) {
// A virtual method. Mark it as reachable so that subclasses, if instantiated, keep
// their overrides. However, we don't mark it live, as a keep rule might not imply that
// the corresponding class is live.
- markVirtualMethodAsReachable(method, holder.isInterface(), null, reason);
+ markVirtualMethodAsReachable(reference, holder.isInterface(), null, reason);
if (holder.isInterface()) {
// Reachability for default methods is based on live subtypes in general. For keep rules,
// we need special handling as we essentially might have live subtypes that are outside of
// the current compilation unit. Keep either the default-method or its implementation
// method.
// TODO(b/120959039): Codify the kept-graph expectations for these cases in tests.
- if (target.isNonAbstractVirtualMethod()) {
- markVirtualMethodAsLive(holder, target, reason);
+ if (definition.isNonAbstractVirtualMethod()) {
+ markVirtualMethodAsLive(target, reason);
} else {
- DexEncodedMethod implementation = target.getDefaultInterfaceMethodImplementation();
+ DexEncodedMethod implementation = definition.getDefaultInterfaceMethodImplementation();
if (implementation != null) {
DexProgramClass companion = getProgramClassOrNull(implementation.holder());
markTypeAsLive(companion, graphReporter.reportCompanionClass(holder, companion));
markVirtualMethodAsLive(
- companion,
- implementation,
- graphReporter.reportCompanionMethod(target, implementation));
+ new ProgramMethod(companion, implementation),
+ graphReporter.reportCompanionMethod(definition, implementation));
}
}
}
} else {
- markMethodAsTargeted(holder, target, reason);
- markDirectStaticOrConstructorMethodAsLive(holder, target, reason);
+ markMethodAsTargeted(target, reason);
+ markDirectStaticOrConstructorMethodAsLive(target, reason);
}
}
@@ -3396,61 +3357,52 @@
}
// Package protected due to entry point from worklist.
- void markMethodAsLive(DexEncodedMethod method, KeepReason reason) {
- assert liveMethods.contains(method);
+ void markMethodAsLive(ProgramMethod method, KeepReason reason) {
+ DexProgramClass holder = method.getHolder();
+ DexEncodedMethod definition = method.getDefinition();
- DexProgramClass clazz = getProgramClassOrNull(method.holder());
- if (clazz == null) {
- return;
+ assert liveMethods.contains(definition);
+
+ if (definition.isStatic()) {
+ markDirectAndIndirectClassInitializersAsLive(method.getHolder());
}
- if (method.isStatic()) {
- markDirectAndIndirectClassInitializersAsLive(clazz);
- }
-
- Set<DexEncodedMethod> superCallTargets = superInvokeDependencies.get(method);
+ ProgramMethodSet superCallTargets = superInvokeDependencies.get(method.getDefinition());
if (superCallTargets != null) {
- for (DexEncodedMethod superCallTarget : superCallTargets) {
+ for (ProgramMethod superCallTarget : superCallTargets) {
if (Log.ENABLED) {
- Log.verbose(getClass(), "Found super invoke constraint on `%s`.", superCallTarget.method);
+ Log.verbose(getClass(), "Found super invoke constraint on `%s`.", superCallTarget);
}
- DexProgramClass targetClass = getProgramClassOrNull(superCallTarget.holder());
- assert targetClass != null;
- if (targetClass != null) {
- markMethodAsTargeted(
- targetClass, superCallTarget, KeepReason.invokedViaSuperFrom(method));
- markVirtualMethodAsLive(
- targetClass, superCallTarget, KeepReason.invokedViaSuperFrom(method));
- }
+ markMethodAsTargeted(superCallTarget, KeepReason.invokedViaSuperFrom(method));
+ markVirtualMethodAsLive(superCallTarget, KeepReason.invokedViaSuperFrom(method));
}
}
markParameterAndReturnTypesAsLive(method);
- processAnnotations(clazz, method);
- method.parameterAnnotationsList.forEachAnnotation(
- annotation -> processAnnotation(clazz, method, annotation));
- method.registerCodeReferences(useRegistryFactory.create(appView, clazz, method, this));
+ processAnnotations(holder, definition);
+ definition.parameterAnnotationsList.forEachAnnotation(
+ annotation -> processAnnotation(holder, definition, annotation));
+ method.registerCodeReferences(useRegistryFactory.create(appView, method, this));
// Add all dependent members to the workqueue.
- enqueueRootItems(rootSet.getDependentItems(method));
+ enqueueRootItems(rootSet.getDependentItems(definition));
// Notify analyses.
analyses.forEach(analysis -> analysis.processNewlyLiveMethod(method));
}
- private void markReferencedTypesAsLive(DexEncodedMethod method) {
+ private void markReferencedTypesAsLive(ProgramMethod method) {
markTypeAsLive(
- method.holder(), clazz -> graphReporter.reportClassReferencedFrom(clazz, method));
+ method.getHolderType(), clazz -> graphReporter.reportClassReferencedFrom(clazz, method));
markParameterAndReturnTypesAsLive(method);
}
-
- private void markParameterAndReturnTypesAsLive(DexEncodedMethod method) {
- for (DexType parameterType : method.method.proto.parameters.values) {
+ private void markParameterAndReturnTypesAsLive(ProgramMethod method) {
+ for (DexType parameterType : method.getDefinition().parameters().values) {
markTypeAsLive(
parameterType, clazz -> graphReporter.reportClassReferencedFrom(clazz, method));
}
markTypeAsLive(
- method.method.proto.returnType,
+ method.getDefinition().returnType(),
clazz -> graphReporter.reportClassReferencedFrom(clazz, method));
}
@@ -3470,22 +3422,20 @@
} else {
workList.enqueueMarkInstantiatedAction(clazz, null, InstantiationReason.KEEP_RULE, witness);
if (clazz.hasDefaultInitializer()) {
- DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer();
+ ProgramMethod defaultInitializer = clazz.getProgramDefaultInitializer();
workList.enqueueMarkReachableDirectAction(
- defaultInitializer.method,
- graphReporter.reportCompatKeepDefaultInitializer(clazz, defaultInitializer));
+ defaultInitializer.getReference(),
+ graphReporter.reportCompatKeepDefaultInitializer(defaultInitializer));
}
}
}
- private void markMethodAsLiveWithCompatRule(DexProgramClass clazz, DexEncodedMethod method) {
- enqueueMarkMethodLiveAction(clazz, method, graphReporter.reportCompatKeepMethod(clazz, method));
+ private void markMethodAsLiveWithCompatRule(ProgramMethod method) {
+ enqueueMarkMethodLiveAction(method, graphReporter.reportCompatKeepMethod(method));
}
- private void handleReflectiveBehavior(DexEncodedMethod method) {
- DexType originHolder = method.holder();
- Origin origin = appInfo.originFor(originHolder);
- IRCode code = method.buildIR(appView, origin);
+ private void handleReflectiveBehavior(ProgramMethod method) {
+ IRCode code = method.buildIR(appView);
InstructionIterator iterator = code.instructionIterator();
while (iterator.hasNext()) {
Instruction instruction = iterator.next();
@@ -3493,7 +3443,7 @@
}
}
- private void handleReflectiveBehavior(DexEncodedMethod method, Instruction instruction) {
+ private void handleReflectiveBehavior(ProgramMethod method, Instruction instruction) {
if (!instruction.isInvokeMethod()) {
return;
}
@@ -3542,10 +3492,10 @@
workList.enqueueMarkInstantiatedAction(
clazz, null, InstantiationReason.REFLECTION, KeepReason.reflectiveUseIn(method));
if (clazz.hasDefaultInitializer()) {
- DexEncodedMethod initializer = clazz.getDefaultInitializer();
+ ProgramMethod initializer = clazz.getProgramDefaultInitializer();
KeepReason reason = KeepReason.reflectiveUseIn(method);
- markMethodAsTargeted(clazz, initializer, reason);
- markDirectStaticOrConstructorMethodAsLive(clazz, initializer, reason);
+ markMethodAsTargeted(initializer, reason);
+ markDirectStaticOrConstructorMethodAsLive(initializer, reason);
}
}
} else if (identifierItem.isDexField()) {
@@ -3575,27 +3525,28 @@
}
} else {
assert identifierItem.isDexMethod();
- DexMethod targetedMethod = identifierItem.asDexMethod();
- DexProgramClass clazz = getProgramClassOrNull(targetedMethod.holder);
+ DexMethod targetedMethodReference = identifierItem.asDexMethod();
+ DexProgramClass clazz = getProgramClassOrNull(targetedMethodReference.holder);
if (clazz == null) {
return;
}
- DexEncodedMethod encodedMethod = appView.definitionFor(targetedMethod);
- if (encodedMethod == null) {
+ DexEncodedMethod targetedMethodDefinition = clazz.lookupMethod(targetedMethodReference);
+ if (targetedMethodDefinition == null) {
return;
}
+ ProgramMethod targetedMethod = new ProgramMethod(clazz, targetedMethodDefinition);
KeepReason reason = KeepReason.reflectiveUseIn(method);
- if (encodedMethod.accessFlags.isStatic() || encodedMethod.accessFlags.isConstructor()) {
- markMethodAsTargeted(clazz, encodedMethod, reason);
- markDirectStaticOrConstructorMethodAsLive(clazz, encodedMethod, reason);
+ if (targetedMethodDefinition.isStatic() || targetedMethodDefinition.isInstanceInitializer()) {
+ markMethodAsTargeted(targetedMethod, reason);
+ markDirectStaticOrConstructorMethodAsLive(targetedMethod, reason);
} else {
- markVirtualMethodAsLive(clazz, encodedMethod, reason);
+ markVirtualMethodAsLive(targetedMethod, reason);
}
}
}
/** Handles reflective uses of {@link Class#newInstance()}. */
- private void handleJavaLangClassNewInstance(DexEncodedMethod method, InvokeMethod invoke) {
+ private void handleJavaLangClassNewInstance(ProgramMethod method, InvokeMethod invoke) {
if (!invoke.isInvokeVirtual()) {
assert false;
return;
@@ -3614,18 +3565,18 @@
if (clazz == null) {
return;
}
- DexEncodedMethod defaultInitializer = clazz.getDefaultInitializer();
+ ProgramMethod defaultInitializer = clazz.getProgramDefaultInitializer();
if (defaultInitializer != null) {
KeepReason reason = KeepReason.reflectiveUseIn(method);
markClassAsInstantiatedWithReason(clazz, reason);
- markMethodAsTargeted(clazz, defaultInitializer, reason);
- markDirectStaticOrConstructorMethodAsLive(clazz, defaultInitializer, reason);
+ markMethodAsTargeted(defaultInitializer, reason);
+ markDirectStaticOrConstructorMethodAsLive(defaultInitializer, reason);
}
}
/** Handles reflective uses of {@link java.lang.reflect.Constructor#newInstance(Object...)}. */
private void handleJavaLangReflectConstructorNewInstance(
- DexEncodedMethod method, InvokeMethod invoke) {
+ ProgramMethod method, InvokeMethod invoke) {
if (!invoke.isInvokeVirtual()) {
assert false;
return;
@@ -3669,11 +3620,11 @@
return;
}
- DexEncodedMethod initializer = null;
+ ProgramMethod initializer = null;
int parametersSize = parametersSizeValue.definition.asConstNumber().getIntValue();
if (parametersSize == 0) {
- initializer = clazz.getDefaultInitializer();
+ initializer = clazz.getProgramDefaultInitializer();
} else {
DexType[] parameterTypes = new DexType[parametersSize];
int missingIndices = parametersSize;
@@ -3711,15 +3662,15 @@
}
if (missingIndices == 0) {
- initializer = clazz.getInitializer(parameterTypes);
+ initializer = clazz.getProgramInitializer(parameterTypes);
}
}
if (initializer != null) {
KeepReason reason = KeepReason.reflectiveUseIn(method);
markClassAsInstantiatedWithReason(clazz, reason);
- markMethodAsTargeted(clazz, initializer, reason);
- markDirectStaticOrConstructorMethodAsLive(clazz, initializer, reason);
+ markMethodAsTargeted(initializer, reason);
+ markDirectStaticOrConstructorMethodAsLive(initializer, reason);
}
}
@@ -3728,7 +3679,7 @@
* Class[], InvocationHandler)}.
*/
private void handleJavaLangReflectProxyNewProxyInstance(
- DexEncodedMethod method, InvokeMethod invoke) {
+ ProgramMethod method, InvokeMethod invoke) {
if (!invoke.isInvokeStatic()) {
assert false;
return;
@@ -3770,7 +3721,7 @@
}
}
- private void handleJavaLangEnumValueOf(DexEncodedMethod method, InvokeMethod invoke) {
+ private void handleJavaLangEnumValueOf(ProgramMethod method, InvokeMethod invoke) {
// The use of java.lang.Enum.valueOf(java.lang.Class, java.lang.String) will indirectly
// access the values() method of the enum class passed as the first argument. The method
// SomeEnumClass.valueOf(java.lang.String) which is generated by javac for all enums will
@@ -3779,13 +3730,12 @@
DexType type = invoke.inValues().get(0).definition.asConstClass().getValue();
DexProgramClass clazz = getProgramClassOrNull(type);
if (clazz != null && clazz.accessFlags.isEnum()) {
- DexProgramClass holder = getProgramClassOrNull(method.holder());
- markEnumValuesAsReachable(clazz, KeepReason.invokedFrom(holder, method));
+ markEnumValuesAsReachable(clazz, KeepReason.invokedFrom(method));
}
}
}
- private void handleServiceLoaderInvocation(DexEncodedMethod method, InvokeMethod invoke) {
+ private void handleServiceLoaderInvocation(ProgramMethod method, InvokeMethod invoke) {
if (invoke.inValues().size() == 0) {
// Should never happen.
return;
@@ -3804,7 +3754,7 @@
+ "` is being passed to the method `"
+ invoke.getInvokedMethod().toSourceString()
+ "`, but was not found in `META-INF/services/`.",
- appInfo.originFor(method.holder())));
+ method.getOrigin()));
}
return;
}
@@ -3877,16 +3827,21 @@
this.register = register;
}
- boolean add(DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
- register.accept(method, reason);
- transitionUnusedInterfaceToLive(clazz);
- return items.add(method);
+ boolean add(ProgramMethod method, KeepReason reason) {
+ DexEncodedMethod definition = method.getDefinition();
+ register.accept(definition, reason);
+ transitionUnusedInterfaceToLive(method.getHolder());
+ return items.add(definition);
}
boolean contains(DexEncodedMethod method) {
return items.contains(method);
}
+ boolean contains(ProgramMethod method) {
+ return contains(method.getDefinition());
+ }
+
Set<DexEncodedMethod> getItems() {
return Collections.unmodifiableSet(items);
}
@@ -3946,7 +3901,7 @@
if (target != null) {
// There is no dispatch on annotations, so only keep what is directly referenced.
if (target.field == field) {
- if (!registerFieldRead(field, DexEncodedMethod.ANNOTATION_REFERENCE)) {
+ if (!registerFieldReadFromAnnotation(field)) {
return false;
}
markStaticFieldAsLive(target, KeepReason.referencedInAnnotation(annotationHolder));
@@ -3983,13 +3938,16 @@
// There is no dispatch on annotations, so only keep what is directly referenced.
if (target.method == method) {
markDirectStaticOrConstructorMethodAsLive(
- holder, target, KeepReason.referencedInAnnotation(annotationHolder));
+ new ProgramMethod(holder, target),
+ KeepReason.referencedInAnnotation(annotationHolder));
}
} else {
target = holder.lookupVirtualMethod(method);
// There is no dispatch on annotations, so only keep what is directly referenced.
if (target != null && target.method == method) {
- markMethodAsTargeted(holder, target, KeepReason.referencedInAnnotation(annotationHolder));
+ markMethodAsTargeted(
+ new ProgramMethod(holder, target),
+ KeepReason.referencedInAnnotation(annotationHolder));
}
}
return false;
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerUseRegistryFactory.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerUseRegistryFactory.java
index d32a130..86acd84 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerUseRegistryFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerUseRegistryFactory.java
@@ -5,15 +5,10 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
public interface EnqueuerUseRegistryFactory {
- UseRegistry create(
- AppView<?> appView,
- DexProgramClass currentHolder,
- DexEncodedMethod currentMethod,
- Enqueuer enqueuer);
+ UseRegistry create(AppView<?> appView, ProgramMethod currentMethod, Enqueuer enqueuer);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 2a46ba3..f5ffc75 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -39,9 +38,9 @@
static class MarkReachableSuperAction extends EnqueuerAction {
final DexMethod target;
- final DexEncodedMethod context;
+ final ProgramMethod context;
- public MarkReachableSuperAction(DexMethod target, DexEncodedMethod context) {
+ public MarkReachableSuperAction(DexMethod target, ProgramMethod context) {
this.target = target;
this.context = context;
}
@@ -70,13 +69,13 @@
static class MarkInstantiatedAction extends EnqueuerAction {
final DexProgramClass target;
- final DexEncodedMethod context;
+ final ProgramMethod context;
final InstantiationReason instantiationReason;
final KeepReason keepReason;
public MarkInstantiatedAction(
DexProgramClass target,
- DexEncodedMethod context,
+ ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason) {
this.target = target;
@@ -122,35 +121,32 @@
}
static class MarkMethodLiveAction extends EnqueuerAction {
- final DexEncodedMethod target;
+ final ProgramMethod method;
final KeepReason reason;
- public MarkMethodLiveAction(DexEncodedMethod target, KeepReason reason) {
- this.target = target;
+ public MarkMethodLiveAction(ProgramMethod method, KeepReason reason) {
+ this.method = method;
this.reason = reason;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.markMethodAsLive(target, reason);
+ enqueuer.markMethodAsLive(method, reason);
}
}
static class MarkMethodKeptAction extends EnqueuerAction {
- final DexProgramClass holder;
- final DexEncodedMethod target;
+ final ProgramMethod target;
final KeepReason reason;
- public MarkMethodKeptAction(
- DexProgramClass holder, DexEncodedMethod target, KeepReason reason) {
- this.holder = holder;
+ public MarkMethodKeptAction(ProgramMethod target, KeepReason reason) {
this.target = target;
this.reason = reason;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.markMethodAsKept(holder, target, reason);
+ enqueuer.markMethodAsKept(target, reason);
}
}
@@ -174,34 +170,31 @@
static class TraceConstClassAction extends EnqueuerAction {
final DexType type;
- final DexEncodedMethod currentMethod;
+ final ProgramMethod context;
- TraceConstClassAction(DexType type, DexEncodedMethod currentMethod) {
+ TraceConstClassAction(DexType type, ProgramMethod context) {
this.type = type;
- this.currentMethod = currentMethod;
+ this.context = context;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.traceConstClass(type, currentMethod);
+ enqueuer.traceConstClass(type, context);
}
}
static class TraceInvokeDirectAction extends EnqueuerAction {
final DexMethod invokedMethod;
- final DexProgramClass currentHolder;
- final DexEncodedMethod currentMethod;
+ final ProgramMethod context;
- TraceInvokeDirectAction(
- DexMethod invokedMethod, DexProgramClass currentHolder, DexEncodedMethod currentMethod) {
+ TraceInvokeDirectAction(DexMethod invokedMethod, ProgramMethod context) {
this.invokedMethod = invokedMethod;
- this.currentHolder = currentHolder;
- this.currentMethod = currentMethod;
+ this.context = context;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.traceInvokeDirect(invokedMethod, new ProgramMethod(currentHolder, currentMethod));
+ enqueuer.traceInvokeDirect(invokedMethod, context);
}
}
@@ -222,16 +215,16 @@
static class TraceStaticFieldReadAction extends EnqueuerAction {
final DexField field;
- final DexEncodedMethod currentMethod;
+ final ProgramMethod context;
- TraceStaticFieldReadAction(DexField field, DexEncodedMethod currentMethod) {
+ TraceStaticFieldReadAction(DexField field, ProgramMethod context) {
this.field = field;
- this.currentMethod = currentMethod;
+ this.context = context;
}
@Override
public void run(Enqueuer enqueuer) {
- enqueuer.traceStaticFieldRead(field, currentMethod);
+ enqueuer.traceStaticFieldRead(field, context);
}
}
@@ -258,7 +251,7 @@
queue.add(new MarkReachableDirectAction(method, reason));
}
- void enqueueMarkReachableSuperAction(DexMethod method, DexEncodedMethod from) {
+ void enqueueMarkReachableSuperAction(DexMethod method, ProgramMethod from) {
queue.add(new MarkReachableSuperAction(method, from));
}
@@ -272,7 +265,7 @@
// Consider updating call sites with the context information to increase precision where possible.
public void enqueueMarkInstantiatedAction(
DexProgramClass clazz,
- DexEncodedMethod context,
+ ProgramMethod context,
InstantiationReason instantiationReason,
KeepReason keepReason) {
assert !clazz.isAnnotation();
@@ -292,16 +285,12 @@
queue.add(new MarkInterfaceInstantiatedAction(clazz, reason));
}
- void enqueueMarkMethodLiveAction(
- DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
- assert method.holder() == clazz.type;
+ void enqueueMarkMethodLiveAction(ProgramMethod method, KeepReason reason) {
queue.add(new MarkMethodLiveAction(method, reason));
}
- void enqueueMarkMethodKeptAction(
- DexProgramClass clazz, DexEncodedMethod method, KeepReason reason) {
- assert method.holder() == clazz.type;
- queue.add(new MarkMethodKeptAction(clazz, method, reason));
+ void enqueueMarkMethodKeptAction(ProgramMethod method, KeepReason reason) {
+ queue.add(new MarkMethodKeptAction(method, reason));
}
void enqueueMarkFieldKeptAction(
@@ -310,23 +299,19 @@
queue.add(new MarkFieldKeptAction(holder, field, witness));
}
- public void enqueueTraceConstClassAction(DexType type, DexEncodedMethod currentMethod) {
- assert currentMethod.isProgramMethod(appView);
- queue.add(new TraceConstClassAction(type, currentMethod));
+ public void enqueueTraceConstClassAction(DexType type, ProgramMethod context) {
+ queue.add(new TraceConstClassAction(type, context));
}
- public void enqueueTraceInvokeDirectAction(
- DexMethod invokedMethod, DexProgramClass currentHolder, DexEncodedMethod currentMethod) {
- assert currentMethod.holder() == currentHolder.type;
- queue.add(new TraceInvokeDirectAction(invokedMethod, currentHolder, currentMethod));
+ public void enqueueTraceInvokeDirectAction(DexMethod invokedMethod, ProgramMethod context) {
+ queue.add(new TraceInvokeDirectAction(invokedMethod, context));
}
public void enqueueTraceNewInstanceAction(DexType type, ProgramMethod context) {
queue.add(new TraceNewInstanceAction(type, context));
}
- public void enqueueTraceStaticFieldRead(DexField field, DexEncodedMethod currentMethod) {
- assert currentMethod.isProgramMethod(appView);
- queue.add(new TraceStaticFieldReadAction(field, currentMethod));
+ public void enqueueTraceStaticFieldRead(DexField field, ProgramMethod context) {
+ queue.add(new TraceStaticFieldReadAction(field, context));
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
index 4ff3594..0e39b4c 100644
--- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
+++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -169,21 +169,19 @@
return KeepReasonWitness.INSTANCE;
}
- public KeepReasonWitness reportCompatKeepDefaultInitializer(
- DexProgramClass holder, DexEncodedMethod defaultInitializer) {
- assert holder.type == defaultInitializer.holder();
- assert holder.getDefaultInitializer() == defaultInitializer;
+ public KeepReasonWitness reportCompatKeepDefaultInitializer(ProgramMethod defaultInitializer) {
+ assert defaultInitializer.getHolder().getDefaultInitializer()
+ == defaultInitializer.getDefinition();
if (keptGraphConsumer != null) {
reportEdge(
- getClassGraphNode(holder.type),
- getMethodGraphNode(defaultInitializer.method),
+ getClassGraphNode(defaultInitializer.getHolderType()),
+ getMethodGraphNode(defaultInitializer.getReference()),
EdgeKind.CompatibilityRule);
}
return KeepReasonWitness.INSTANCE;
}
- public KeepReasonWitness reportCompatKeepMethod(DexProgramClass holder, DexEncodedMethod method) {
- assert holder.type == method.holder();
+ public KeepReasonWitness reportCompatKeepMethod(ProgramMethod method) {
// TODO(b/141729349): This compat rule is from the method to itself and has not edge. Fix it.
// The rule is stating that if the method is targeted it is live. Since such an edge does
// not contribute to additional information in the kept graph as it stands (no distinction
@@ -192,10 +190,10 @@
}
public KeepReasonWitness reportCompatInstantiated(
- DexProgramClass instantiated, DexEncodedMethod method) {
+ DexProgramClass instantiated, ProgramMethod method) {
if (keptGraphConsumer != null) {
reportEdge(
- getMethodGraphNode(method.method),
+ getMethodGraphNode(method.getReference()),
getClassGraphNode(instantiated.type),
EdgeKind.CompatibilityRule);
}
@@ -212,10 +210,9 @@
return KeepReasonWitness.INSTANCE;
}
- public KeepReasonWitness reportClassReferencedFrom(
- DexProgramClass clazz, DexEncodedMethod method) {
+ public KeepReasonWitness reportClassReferencedFrom(DexProgramClass clazz, ProgramMethod method) {
if (keptGraphConsumer != null) {
- MethodGraphNode source = getMethodGraphNode(method.method);
+ MethodGraphNode source = getMethodGraphNode(method.getReference());
ClassGraphNode target = getClassGraphNode(clazz.type);
return reportEdge(source, target, EdgeKind.ReferencedFrom);
}
@@ -232,13 +229,12 @@
}
public KeepReasonWitness reportReachableClassInitializer(
- DexProgramClass clazz, DexEncodedMethod initializer) {
+ DexProgramClass clazz, ProgramMethod initializer) {
if (initializer != null) {
- assert clazz.type == initializer.holder();
- assert initializer.isClassInitializer();
+ assert initializer.getDefinition().isClassInitializer();
if (keptGraphConsumer != null) {
ClassGraphNode source = getClassGraphNode(clazz.type);
- MethodGraphNode target = getMethodGraphNode(initializer.method);
+ MethodGraphNode target = getMethodGraphNode(initializer.getReference());
return reportEdge(source, target, EdgeKind.ReachableFromLiveType);
}
} else {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepReason.java b/src/main/java/com/android/tools/r8/shaking/KeepReason.java
index 62a67ee..31f7611 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepReason.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepReason.java
@@ -29,10 +29,18 @@
return new InstantiatedIn(method);
}
+ static KeepReason instantiatedIn(ProgramMethod method) {
+ return new InstantiatedIn(method.getDefinition());
+ }
+
public static KeepReason invokedViaSuperFrom(DexEncodedMethod from) {
return new InvokedViaSuper(from);
}
+ public static KeepReason invokedViaSuperFrom(ProgramMethod from) {
+ return new InvokedViaSuper(from.getDefinition());
+ }
+
public static KeepReason reachableFromLiveType(DexType type) {
return new ReachableFromLiveType(type);
}
@@ -45,12 +53,12 @@
return invokedFrom(context.getHolder(), context.getDefinition());
}
- public static KeepReason invokedFromLambdaCreatedIn(DexEncodedMethod method) {
- return new InvokedFromLambdaCreatedIn(method);
+ public static KeepReason invokedFromLambdaCreatedIn(ProgramMethod method) {
+ return new InvokedFromLambdaCreatedIn(method.getDefinition());
}
- public static KeepReason fieldReferencedIn(DexEncodedMethod method) {
- return new ReferencedFrom(method);
+ public static KeepReason fieldReferencedIn(ProgramMethod method) {
+ return new ReferencedFrom(method.getDefinition());
}
public static KeepReason referencedInAnnotation(DexItem holder) {
@@ -65,16 +73,16 @@
return false;
}
- public static KeepReason targetedBySuperFrom(DexEncodedMethod from) {
- return new TargetedBySuper(from);
+ public static KeepReason targetedBySuperFrom(ProgramMethod from) {
+ return new TargetedBySuper(from.getDefinition());
}
- public static KeepReason reflectiveUseIn(DexEncodedMethod method) {
- return new ReflectiveUseFrom(method);
+ public static KeepReason reflectiveUseIn(ProgramMethod method) {
+ return new ReflectiveUseFrom(method.getDefinition());
}
- public static KeepReason methodHandleReferencedIn(DexEncodedMethod method) {
- return new MethodHandleReferencedFrom(method);
+ public static KeepReason methodHandleReferencedIn(ProgramMethod method) {
+ return new MethodHandleReferencedFrom(method.getDefinition());
}
private abstract static class BasedOnOtherMethod extends KeepReason {
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
index e686f98..205cf71 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -18,7 +19,9 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.utils.BooleanBox;
import java.util.Set;
import java.util.function.Consumer;
@@ -39,30 +42,28 @@
public void run(Set<DexType> roots) {
for (DexType type : roots) {
- DexClass clazz = appInfo.definitionFor(type);
+ DexProgramClass clazz = asProgramClassOrNull(appInfo.definitionFor(type));
// Should only happen for library classes, which are filtered out.
assert clazz != null;
consumer.accept(type);
// Super and interfaces are live, no need to add them.
traceAnnotationsDirectDependencies(clazz.annotations());
clazz.forEachField(field -> consumer.accept(field.field.type));
- clazz.forEachMethod(method -> {
- traceMethodDirectDependencies(method.method, consumer);
- method.registerCodeReferences(codeDirectReferenceCollector);
- });
+ clazz.forEachProgramMethodMatching(
+ definition -> {
+ traceMethodDirectDependencies(definition.getReference(), consumer);
+ return definition.hasCode();
+ },
+ method -> method.registerCodeReferences(codeDirectReferenceCollector));
}
}
- public void runOnCode(DexEncodedMethod method) {
+ public void runOnCode(ProgramMethod method) {
method.registerCodeReferences(codeDirectReferenceCollector);
}
- private static class BooleanBox {
- boolean value = false;
- }
-
public static boolean hasReferencesOutsideFromCode(
- AppInfoWithClassHierarchy appInfo, DexEncodedMethod method, Set<DexType> classes) {
+ AppInfoWithClassHierarchy appInfo, ProgramMethod method, Set<DexType> classes) {
BooleanBox result = new BooleanBox();
@@ -73,13 +74,13 @@
if (baseType.isClassType() && !classes.contains(baseType)) {
DexClass cls = appInfo.definitionFor(baseType);
if (cls != null && cls.isProgramClass()) {
- result.value = true;
+ result.set(true);
}
}
})
.runOnCode(method);
- return result.value;
+ return result.get();
}
private void traceAnnotationsDirectDependencies(DexAnnotationSet annotations) {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 846710b..e105350 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -1314,15 +1314,20 @@
public void forEachDependentInstanceConstructor(
DexProgramClass clazz,
AppView<?> appView,
- Consumer3<DexProgramClass, DexEncodedMethod, Set<ProguardKeepRuleBase>> fn) {
+ Consumer3<DexProgramClass, ProgramMethod, Set<ProguardKeepRuleBase>> fn) {
getDependentItems(clazz)
.forEach(
(reference, reasons) -> {
- DexDefinition definition = appView.definitionFor(reference);
- if (definition != null
- && definition.isDexEncodedMethod()
- && definition.asDexEncodedMethod().isInstanceInitializer()) {
- fn.accept(clazz, definition.asDexEncodedMethod(), reasons);
+ if (reference.isDexMethod()) {
+ DexMethod methodReference = reference.asDexMethod();
+ DexProgramClass holder =
+ asProgramClassOrNull(appView.definitionForHolder(methodReference));
+ if (holder != null) {
+ ProgramMethod method = holder.lookupProgramMethod(methodReference);
+ if (method != null && method.getDefinition().isInstanceInitializer()) {
+ fn.accept(clazz, method, reasons);
+ }
+ }
}
});
}
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 5031d82..dc69de3 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.utils.MethodJavaSignatureEquivalence;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.SingletonEquivalence;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.BiMap;
@@ -171,8 +172,8 @@
}
boolean classHasSynchronizedMethods = false;
for (DexEncodedMethod method : clazz.methods()) {
- assert !hasSynchronizedMethods || !method.accessFlags.isSynchronized();
- classHasSynchronizedMethods |= method.accessFlags.isSynchronized();
+ assert !hasSynchronizedMethods || !method.isSynchronized();
+ classHasSynchronizedMethods |= method.isSynchronized();
Wrapper<DexMethod> wrapper = methodEquivalence.wrap(method.method);
methodBuckets.add(wrapper);
}
@@ -443,14 +444,17 @@
// Check that no methods access package-private or protected members.
IllegalAccessDetector registry = new IllegalAccessDetector(appView, clazz);
- for (DexEncodedMethod method : clazz.methods()) {
- registry.setContext(method);
- method.registerCodeReferences(registry);
- if (registry.foundIllegalAccess()) {
- return false;
- }
- }
- return true;
+ TraversalContinuation result =
+ clazz.traverseProgramMethods(
+ method -> {
+ registry.setContext(method);
+ method.registerCodeReferences(registry);
+ if (registry.foundIllegalAccess()) {
+ return TraversalContinuation.BREAK;
+ }
+ return TraversalContinuation.CONTINUE;
+ });
+ return result.shouldContinue();
}
private void moveMembersFromSourceToTarget(
@@ -465,8 +469,8 @@
// TODO(b/136457753) This check is a bit weird for protected, since it is moving access.
assert targetClass.accessFlags.isAtLeastAsVisibleAs(sourceClass.accessFlags);
- assert sourceClass.instanceFields().size() == 0;
- assert targetClass.instanceFields().size() == 0;
+ assert sourceClass.instanceFields().isEmpty();
+ assert targetClass.instanceFields().isEmpty();
numberOfMergedClasses++;
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 7c679e0..6f2010c 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -291,13 +291,13 @@
// Also some other kinds of methods cannot be abstract, so keep them around.
boolean allowAbstract =
(!options.canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug()
- || clazz.accessFlags.isAbstract())
- && !method.accessFlags.isFinal()
+ || clazz.isAbstract())
+ && !method.isFinal()
&& !method.accessFlags.isNative()
&& !method.accessFlags.isStrict()
- && !method.accessFlags.isSynchronized()
+ && !method.isSynchronized()
&& !method.accessFlags.isPrivate()
- && !method.accessFlags.isStatic()
+ && !method.isStatic()
&& !appInfo.failedResolutionTargets.contains(method.method);
// Private methods and static methods can only be targeted yet non-live as the result of
// an invalid invoke. They will not actually be called at runtime but we have to keep them
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index bb90d42..31d8074 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
@@ -32,6 +33,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.SubtypingInfo;
@@ -51,6 +53,7 @@
import com.android.tools.r8.utils.FieldSignatureEquivalence;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.Iterables;
@@ -376,19 +379,21 @@
// * Have access to the no-arg constructor of its first non-serializable superclass
return false;
}
- for (DexEncodedMethod method : sourceClass.directMethods()) {
- // We rename constructors to private methods and mark them to be forced-inlined, so we have to
- // check if we can force-inline all constructors.
- if (method.isInstanceInitializer()) {
- AbortReason reason = disallowInlining(method, targetClass.type);
- if (reason != null) {
- // Cannot guarantee that markForceInline() will work.
- if (Log.ENABLED) {
- reason.printLogMessageForClass(sourceClass);
- }
- return false;
- }
- }
+ TraversalContinuation result =
+ sourceClass.traverseProgramInstanceInitializers(
+ method -> {
+ AbortReason reason = disallowInlining(method, targetClass.type);
+ if (reason != null) {
+ // Cannot guarantee that markForceInline() will work.
+ if (Log.ENABLED) {
+ reason.printLogMessageForClass(sourceClass);
+ }
+ return TraversalContinuation.BREAK;
+ }
+ return TraversalContinuation.CONTINUE;
+ });
+ if (result.shouldBreak()) {
+ return false;
}
if (sourceClass.getEnclosingMethod() != null || !sourceClass.getInnerClasses().isEmpty()) {
// TODO(b/147504070): Consider merging of enclosing-method and inner-class attributes.
@@ -472,15 +477,13 @@
return true;
}
- private boolean mergeMayLeadToIllegalAccesses(DexClass source, DexClass target) {
+ private boolean mergeMayLeadToIllegalAccesses(DexProgramClass source, DexProgramClass target) {
if (source.type.isSamePackage(target.type)) {
// When merging two classes from the same package, we only need to make sure that [source]
// does not get less visible, since that could make a valid access to [source] from another
// package illegal after [source] has been merged into [target].
- int accessLevel =
- source.accessFlags.isPrivate() ? 0 : (source.accessFlags.isPublic() ? 2 : 1);
- int otherAccessLevel =
- target.accessFlags.isPrivate() ? 0 : (target.accessFlags.isPublic() ? 2 : 1);
+ int accessLevel = source.isPrivate() ? 0 : (source.isPublic() ? 2 : 1);
+ int otherAccessLevel = target.isPrivate() ? 0 : (target.isPublic() ? 2 : 1);
return accessLevel > otherAccessLevel;
}
@@ -489,22 +492,22 @@
// [source] are either private or public.
//
// (Deliberately not checking all accesses to [source] since that would be expensive.)
- if (!target.accessFlags.isPublic()) {
+ if (!target.isPublic()) {
return true;
}
for (DexEncodedField field : source.fields()) {
- if (!(field.accessFlags.isPublic() || field.accessFlags.isPrivate())) {
+ if (!(field.isPublic() || field.isPrivate())) {
return true;
}
}
for (DexEncodedMethod method : source.methods()) {
- if (!(method.accessFlags.isPublic() || method.accessFlags.isPrivate())) {
+ if (!(method.isPublic() || method.isPrivate())) {
return true;
}
// Check if the target is overriding and narrowing the access.
- if (method.accessFlags.isPublic()) {
+ if (method.isPublic()) {
DexEncodedMethod targetOverride = target.lookupVirtualMethod(method.method);
- if (targetOverride != null && !targetOverride.accessFlags.isPublic()) {
+ if (targetOverride != null && !targetOverride.isPublic()) {
return true;
}
}
@@ -513,15 +516,17 @@
// [source] will continue to work. This is guaranteed if the methods of [source] do not access
// any private or protected classes or members from the current package of [source].
IllegalAccessDetector registry = new IllegalAccessDetector(appView, source);
- for (DexEncodedMethod method : source.methods()) {
- registry.setContext(method);
- method.registerCodeReferences(registry);
- if (registry.foundIllegalAccess()) {
- return true;
- }
- }
-
- return false;
+ TraversalContinuation result =
+ source.traverseProgramMethods(
+ method -> {
+ registry.setContext(method);
+ method.registerCodeReferences(registry);
+ if (registry.foundIllegalAccess()) {
+ return TraversalContinuation.BREAK;
+ }
+ return TraversalContinuation.CONTINUE;
+ });
+ return result.shouldBreak();
}
private Collection<DexMethod> getInvokes() {
@@ -1650,15 +1655,16 @@
}
}
- private AbortReason disallowInlining(DexEncodedMethod method, DexType invocationContext) {
+ private AbortReason disallowInlining(ProgramMethod method, DexType invocationContext) {
if (appView.options().enableInlining) {
- if (method.getCode().isCfCode()) {
- CfCode code = method.getCode().asCfCode();
+ Code code = method.getDefinition().getCode();
+ if (code.isCfCode()) {
+ CfCode cfCode = code.asCfCode();
ConstraintWithTarget constraint =
- code.computeInliningConstraint(
+ cfCode.computeInliningConstraint(
method,
appView,
- new SingleTypeMapperGraphLense(method.holder(), invocationContext),
+ new SingleTypeMapperGraphLense(method.getHolderType(), invocationContext),
invocationContext);
if (constraint == ConstraintWithTarget.NEVER) {
return AbortReason.UNSAFE_INLINING;
@@ -1761,8 +1767,8 @@
// as [source].
public static class IllegalAccessDetector extends UseRegistry {
- private boolean foundIllegalAccess = false;
- private DexMethod context = null;
+ private boolean foundIllegalAccess;
+ private ProgramMethod context;
private final AppView<?> appView;
private final DexClass source;
@@ -1777,8 +1783,8 @@
return foundIllegalAccess;
}
- public void setContext(DexEncodedMethod context) {
- this.context = context.method;
+ public void setContext(ProgramMethod context) {
+ this.context = context;
}
private boolean checkFieldReference(DexField field) {
@@ -1840,7 +1846,7 @@
public boolean registerInvokeVirtual(DexMethod method) {
assert context != null;
GraphLenseLookupResult lookup =
- appView.graphLense().lookupMethod(method, context, Type.VIRTUAL);
+ appView.graphLense().lookupMethod(method, context.getReference(), Type.VIRTUAL);
return checkMethodReference(lookup.getMethod());
}
@@ -1848,7 +1854,7 @@
public boolean registerInvokeDirect(DexMethod method) {
assert context != null;
GraphLenseLookupResult lookup =
- appView.graphLense().lookupMethod(method, context, Type.DIRECT);
+ appView.graphLense().lookupMethod(method, context.getReference(), Type.DIRECT);
return checkMethodReference(lookup.getMethod());
}
@@ -1856,7 +1862,7 @@
public boolean registerInvokeStatic(DexMethod method) {
assert context != null;
GraphLenseLookupResult lookup =
- appView.graphLense().lookupMethod(method, context, Type.STATIC);
+ appView.graphLense().lookupMethod(method, context.getReference(), Type.STATIC);
return checkMethodReference(lookup.getMethod());
}
@@ -1864,7 +1870,7 @@
public boolean registerInvokeInterface(DexMethod method) {
assert context != null;
GraphLenseLookupResult lookup =
- appView.graphLense().lookupMethod(method, context, Type.INTERFACE);
+ appView.graphLense().lookupMethod(method, context.getReference(), Type.INTERFACE);
return checkMethodReference(lookup.getMethod());
}
@@ -1872,7 +1878,7 @@
public boolean registerInvokeSuper(DexMethod method) {
assert context != null;
GraphLenseLookupResult lookup =
- appView.graphLense().lookupMethod(method, context, Type.SUPER);
+ appView.graphLense().lookupMethod(method, context.getReference(), Type.SUPER);
return checkMethodReference(lookup.getMethod());
}
diff --git a/src/main/java/com/android/tools/r8/utils/BooleanBox.java b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
new file mode 100644
index 0000000..d31e352
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/BooleanBox.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2020, 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;
+
+public class BooleanBox {
+
+ private boolean value;
+
+ public BooleanBox() {}
+
+ public BooleanBox(boolean initialValue) {
+ set(initialValue);
+ }
+
+ public boolean get() {
+ return value;
+ }
+
+ public void set(boolean value) {
+ this.value = value;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/IntBox.java b/src/main/java/com/android/tools/r8/utils/IntBox.java
new file mode 100644
index 0000000..9f4ac85
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/IntBox.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2020, 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;
+
+public class IntBox {
+
+ private int value;
+
+ public IntBox() {}
+
+ public IntBox(int initialValue) {
+ set(initialValue);
+ }
+
+ public int get() {
+ return value;
+ }
+
+ public int getAndIncrement() {
+ return value++;
+ }
+
+ public void set(int value) {
+ this.value = value;
+ }
+}
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 7e34093..62aa29a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
@@ -47,6 +48,7 @@
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.IROrdering.IdentityIROrdering;
import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
@@ -60,7 +62,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
@@ -254,7 +255,7 @@
public boolean enableKotlinMetadataRewritingForRenamedClasses = true;
public boolean encodeChecksums = false;
public BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true;
- public boolean enableCfInterfaceMethodDesugaring = false;
+ public boolean cfToCfDesugar = false;
public int callGraphLikelySpuriousCallEdgeThreshold = 50;
@@ -375,7 +376,8 @@
}
public boolean shouldKeepStackMapTable() {
- return isDesugaredLibraryCompilation()
+ assert cfToCfDesugar || isRelocatorCompilation() || getProguardConfiguration() != null;
+ return cfToCfDesugar
|| isRelocatorCompilation()
|| getProguardConfiguration().getKeepAttributes().stackMapTable;
}
@@ -645,8 +647,8 @@
private final Map<Origin, List<InvalidParameterAnnotationInfo>> warningInvalidParameterAnnotations
= new HashMap<>();
- private final Map<Origin, List<Pair<DexEncodedMethod, String>>> warningInvalidDebugInfo
- = new HashMap<>();
+ private final Map<Origin, List<Pair<ProgramMethod, String>>> warningInvalidDebugInfo =
+ new HashMap<>();
// Don't read code from dex files. Used to extract non-code information from vdex files where
// the code contains unsupported byte codes.
@@ -900,7 +902,7 @@
}
public void warningInvalidDebugInfo(
- DexEncodedMethod method, Origin origin, InvalidDebugInfoException e) {
+ ProgramMethod method, Origin origin, InvalidDebugInfoException e) {
if (invalidDebugInfoFatal) {
throw new CompilationError("Fatal warning: Invalid debug info", e);
}
@@ -962,7 +964,7 @@
}
if (warningInvalidDebugInfo.size() > 0) {
int count = 0;
- for (List<Pair<DexEncodedMethod, String>> methods : warningInvalidDebugInfo.values()) {
+ for (List<Pair<ProgramMethod, String>> methods : warningInvalidDebugInfo.values()) {
count += methods.size();
}
reporter.info(
@@ -972,7 +974,7 @@
+ (count == 1 ? " method." : " methods.")));
for (Origin origin : new TreeSet<>(warningInvalidDebugInfo.keySet())) {
StringBuilder builder = new StringBuilder("Methods with invalid locals information:");
- for (Pair<DexEncodedMethod, String> method : warningInvalidDebugInfo.get(origin)) {
+ for (Pair<ProgramMethod, String> method : warningInvalidDebugInfo.get(origin)) {
builder.append("\n ").append(method.getFirst().toSourceString());
builder.append("\n ").append(method.getSecond());
}
@@ -1089,7 +1091,7 @@
public BiConsumer<AppInfoWithLiveness, Enqueuer.Mode> enqueuerInspector = null;
- public Consumer<Deque<Collection<DexEncodedMethod>>> waveModifier = waves -> {};
+ public Consumer<Deque<ProgramMethodSet>> waveModifier = waves -> {};
/**
* If this flag is enabled, we will also compute the set of possible targets for invoke-
@@ -1183,7 +1185,7 @@
public int numberOfProguardIfRuleMemberEvaluations = 0;
}
- public Consumer<DexEncodedMethod> callSiteOptimizationInfoInspector = null;
+ public Consumer<ProgramMethod> callSiteOptimizationInfoInspector = null;
}
@VisibleForTesting
@@ -1276,7 +1278,7 @@
}
return desugarState == DesugarState.ON
&& interfaceMethodDesugaring == OffOrAuto.Auto
- && (!canUseDefaultAndStaticInterfaceMethods() || enableCfInterfaceMethodDesugaring);
+ && (!canUseDefaultAndStaticInterfaceMethods() || cfToCfDesugar);
}
public boolean isStringSwitchConversionEnabled() {
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index f570956..f941485 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -16,6 +16,15 @@
return list.get(0);
}
+ public static <T> int firstIndexMatching(List<T> list, Predicate<T> tester) {
+ for (int i = 0; i < list.size(); i++) {
+ if (tester.test(list.get(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
public static <T> T last(List<T> list) {
return list.get(list.size() - 1);
}
@@ -37,6 +46,15 @@
return result;
}
+ public static <T> boolean removeFirstMatch(List<T> list, Predicate<T> element) {
+ int index = firstIndexMatching(list, element);
+ if (index >= 0) {
+ list.remove(index);
+ return true;
+ }
+ return false;
+ }
+
public static <T extends Comparable<T>> boolean verifyListIsOrdered(List<T> list) {
for (int i = list.size() - 1; i > 0; i--) {
if (list.get(i).compareTo(list.get(i - 1)) < 0) {
diff --git a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
index e6076ca..1349732 100644
--- a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
@@ -24,6 +24,13 @@
return processItemsWithResults(items::forEach, consumer, executorService);
}
+ public static <T, U, R, E extends Exception> Collection<R> processItemsWithResults(
+ Map<T, U> items, ThrowingBiFunction<T, U, R, E> consumer, ExecutorService executorService)
+ throws ExecutionException {
+ return processItemsWithResults(
+ items.entrySet(), arg -> consumer.apply(arg.getKey(), arg.getValue()), executorService);
+ }
+
public static <T, R, E extends Exception> Collection<R> processItemsWithResults(
ForEachable<T> items, ThrowingFunction<T, R, E> consumer, ExecutorService executorService)
throws ExecutionException {
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java b/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java
new file mode 100644
index 0000000..7cfccf0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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;
+
+/**
+ * Similar to a {@link java.util.function.BiFunction} but throws a single {@link Throwable}.
+ *
+ * @param <S> the type of the first input
+ * @param <T> the type of the second input
+ * @param <E> the type of the {@link Throwable}
+ */
+@FunctionalInterface
+public interface ThrowingBiFunction<S, T, R, E extends Throwable> {
+ R apply(S s, T t) throws E;
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
new file mode 100644
index 0000000..b76c14c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, 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.collections;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.Sets;
+import java.util.Set;
+
+public class LongLivedProgramMethodSetBuilder {
+
+ private Set<DexMethod> methods = Sets.newIdentityHashSet();
+
+ public LongLivedProgramMethodSetBuilder() {}
+
+ public void add(ProgramMethod method) {
+ methods.add(method.getReference());
+ }
+
+ public void addAll(Iterable<ProgramMethod> methods) {
+ methods.forEach(this::add);
+ }
+
+ public ProgramMethodSet build(AppView<AppInfoWithLiveness> appView) {
+ ProgramMethodSet result = ProgramMethodSet.create(methods.size());
+ for (DexMethod oldMethod : methods) {
+ DexMethod method = appView.graphLense().getRenamedMethodSignature(oldMethod);
+ DexProgramClass holder = appView.definitionForHolder(method).asProgramClass();
+ result.createAndAdd(holder, holder.lookupMethod(method));
+ }
+ return result;
+ }
+
+ public boolean isEmpty() {
+ return methods.isEmpty();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
new file mode 100644
index 0000000..1795899
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2020, 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.collections;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+public class ProgramMethodSet implements Iterable<ProgramMethod> {
+
+ private static final ProgramMethodSet EMPTY = new ProgramMethodSet(ImmutableMap.of());
+
+ private Map<DexMethod, ProgramMethod> backing;
+
+ private ProgramMethodSet(Map<DexMethod, ProgramMethod> backing) {
+ this.backing = backing;
+ }
+
+ public static ProgramMethodSet create() {
+ return new ProgramMethodSet(new IdentityHashMap<>());
+ }
+
+ public static ProgramMethodSet create(int capacity) {
+ return new ProgramMethodSet(new IdentityHashMap<>(capacity));
+ }
+
+ public static ProgramMethodSet create(ProgramMethod element) {
+ ProgramMethodSet result = create();
+ result.add(element);
+ return result;
+ }
+
+ public static ProgramMethodSet createConcurrent() {
+ return new ProgramMethodSet(new ConcurrentHashMap<>());
+ }
+
+ public static ProgramMethodSet createLinked() {
+ return new ProgramMethodSet(new LinkedHashMap<>());
+ }
+
+ public static ProgramMethodSet empty() {
+ return EMPTY;
+ }
+
+ public boolean add(ProgramMethod method) {
+ ProgramMethod existing = backing.put(method.getReference(), method);
+ assert existing == null || existing.isStructurallyEqualTo(method);
+ return existing == null;
+ }
+
+ public void addAll(Iterable<ProgramMethod> methods) {
+ methods.forEach(this::add);
+ }
+
+ public void addAll(ProgramMethodSet methods) {
+ backing.putAll(methods.backing);
+ }
+
+ public boolean createAndAdd(DexProgramClass clazz, DexEncodedMethod definition) {
+ return add(new ProgramMethod(clazz, definition));
+ }
+
+ public boolean contains(DexEncodedMethod method) {
+ return backing.containsKey(method.getReference());
+ }
+
+ public boolean contains(ProgramMethod method) {
+ return backing.containsKey(method.getReference());
+ }
+
+ public void clear() {
+ backing.clear();
+ }
+
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ @Override
+ public Iterator<ProgramMethod> iterator() {
+ return backing.values().iterator();
+ }
+
+ public boolean remove(DexMethod method) {
+ ProgramMethod existing = backing.remove(method);
+ return existing != null;
+ }
+
+ public boolean remove(DexEncodedMethod method) {
+ return remove(method.getReference());
+ }
+
+ public int size() {
+ return backing.size();
+ }
+
+ public Stream<ProgramMethod> stream() {
+ return backing.values().stream();
+ }
+
+ public Set<DexEncodedMethod> toDefinitionSet() {
+ assert backing instanceof IdentityHashMap;
+ Set<DexEncodedMethod> definitions = Sets.newIdentityHashSet();
+ forEach(method -> definitions.add(method.getDefinition()));
+ return definitions;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index d6732bd..edfb00c 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -19,12 +19,12 @@
extends TestCompilerBuilder<
D8Command, Builder, D8TestCompileResult, D8TestRunResult, D8TestBuilder> {
- private D8TestBuilder(TestState state, Builder builder) {
- super(state, builder, Backend.DEX);
+ private D8TestBuilder(TestState state, Builder builder, Backend backend) {
+ super(state, builder, backend);
}
- public static D8TestBuilder create(TestState state) {
- return new D8TestBuilder(state, D8Command.builder(state.getDiagnosticsHandler()));
+ public static D8TestBuilder create(TestState state, Backend backend) {
+ return new D8TestBuilder(state, D8Command.builder(state.getDiagnosticsHandler()), backend);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 7c3ddff..7938666 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -134,8 +134,12 @@
return ExternalR8TestBuilder.create(new TestState(temp), backend, runtime);
}
+ public static D8TestBuilder testForD8(TemporaryFolder temp, Backend backend) {
+ return D8TestBuilder.create(new TestState(temp), backend);
+ }
+
public static D8TestBuilder testForD8(TemporaryFolder temp) {
- return D8TestBuilder.create(new TestState(temp));
+ return D8TestBuilder.create(new TestState(temp), Backend.DEX);
}
public static DXTestBuilder testForDX(TemporaryFolder temp) {
@@ -171,7 +175,11 @@
}
public D8TestBuilder testForD8() {
- return testForD8(temp);
+ return testForD8(temp, Backend.DEX);
+ }
+
+ public D8TestBuilder testForD8(Backend backend) {
+ return testForD8(temp, backend);
}
public DXTestBuilder testForDX() {
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index 44f046b..eba971d 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -50,7 +50,11 @@
@Override
public void warning(Diagnostic warning) {
- warnings.add(warning);
+ // When testing D8 with class file output this warning is always emitted. Discard this, as
+ // for tests this is not relevant.
+ if (!warning.equals("Compiling to Java class files with D8 is not officially supported")) {
+ warnings.add(warning);
+ }
}
@Override
@@ -58,14 +62,17 @@
errors.add(error);
}
+ @Override
public List<Diagnostic> getInfos() {
return infos;
}
+ @Override
public List<Diagnostic> getWarnings() {
return warnings;
}
+ @Override
public List<Diagnostic> getErrors() {
return errors;
}
@@ -80,6 +87,7 @@
messages.size());
}
+ @Override
public TestDiagnosticMessages assertNoMessages() {
assertEmpty("info", getInfos());
assertEmpty("warning", getWarnings());
@@ -87,6 +95,7 @@
return this;
}
+ @Override
public TestDiagnosticMessages assertOnlyInfos() {
assertNotEquals(0, getInfos().size());
assertEmpty("warning", getWarnings());
@@ -94,6 +103,7 @@
return this;
}
+ @Override
public TestDiagnosticMessages assertOnlyWarnings() {
assertEmpty("info", getInfos());
assertNotEquals(0, getWarnings().size());
@@ -101,6 +111,7 @@
return this;
}
+ @Override
public TestDiagnosticMessages assertOnlyErrors() {
assertEmpty("info", getInfos());
assertEmpty("warning", getWarnings());
@@ -108,16 +119,19 @@
return this;
}
+ @Override
public TestDiagnosticMessages assertInfosCount(int count) {
assertEquals(count, getInfos().size());
return this;
}
+ @Override
public TestDiagnosticMessages assertWarningsCount(int count) {
assertEquals(count, getWarnings().size());
return this;
}
+ @Override
public TestDiagnosticMessages assertErrorsCount(int count) {
assertEquals(count, getErrors().size());
return this;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 5c50407..c992015 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -171,7 +171,7 @@
public static final Path R8LIB_EXCLUDE_DEPS_JAR = Paths.get(LIBS_DIR, "r8lib-exclude-deps.jar");
public static final Path R8LIB_EXCLUDE_DEPS_MAP =
Paths.get(LIBS_DIR, "r8lib-exclude-deps.jar.map");
- public static final Path DEPS = Paths.get(LIBS_DIR, "deps.jar");
+ public static final Path DEPS = Paths.get(LIBS_DIR, "deps_all.jar");
public static final Path DESUGAR_LIB_CONVERSIONS =
Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
diff --git a/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java b/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java
index 07a33ab..c25dc40 100644
--- a/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java
+++ b/src/test/java/com/android/tools/r8/cf/GetClassLdcClassTest.java
@@ -116,11 +116,7 @@
}
private static int getVersion(CodeInspector inspector, Class<?> clazz) {
- return inspector
- .clazz(clazz)
- .getDexProgramClass()
- .asProgramClass()
- .getInitialClassFileVersion();
+ return inspector.clazz(clazz).getDexProgramClass().getInitialClassFileVersion();
}
private static void checkVersion(CodeInspector inspector, Class<?> clazz, int version) {
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
index 8769dc2..7cde792 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithUnderscoreThisTestRunner.java
@@ -120,7 +120,7 @@
internalOptions -> {
if (parameters.isCfRuntime()) {
internalOptions.desugarState = DesugarState.ON;
- internalOptions.enableCfInterfaceMethodDesugaring = true;
+ internalOptions.cfToCfDesugar = true;
}
});
if (parameters.isDexRuntime()) {
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
index ec742ee..e8ac332 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFile.java
@@ -4,16 +4,11 @@
package com.android.tools.r8.desugar;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
import org.junit.Test;
@@ -23,45 +18,43 @@
@RunWith(Parameterized.class)
public class DesugarToClassFile extends TestBase {
- private final TestParameters parameters;
-
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
+ private final TestParameters parameters;
+
public DesugarToClassFile(TestParameters parameters) {
this.parameters = parameters;
}
- private void checkSomething(CodeInspector inspector) {
- ClassSubject classSubject = inspector.clazz(TestClass.class);
- assertThat(classSubject, isPresent());
+ private void checkHasCompanionClass(CodeInspector inspector) {
+ assertTrue(
+ inspector.allClasses().stream()
+ .anyMatch(subject -> subject.getOriginalName().endsWith("$-CC")));
}
- private void checkDiagnostics(TestDiagnosticMessages messages) {
- messages.assertOnlyWarnings();
- messages.assertWarningsCount(1);
- assertThat(
- messages.getWarnings().get(0).getDiagnosticMessage(),
- containsString("not officially supported"));
+ private void checkHasLambdaClass(CodeInspector inspector) {
+ assertTrue(
+ inspector.allClasses().stream()
+ .anyMatch(subject -> subject.getOriginalName().contains("-$$Lambda$")));
}
@Test
public void test() throws Exception {
// Use D8 to desugar with Java classfile output.
Path jar =
- testForD8()
+ testForD8(Backend.CF)
.addInnerClasses(DesugarToClassFile.class)
.setMinApi(parameters.getApiLevel())
- .setOutputMode(OutputMode.ClassFile)
.compile()
- .inspectDiagnosticMessages(this::checkDiagnostics)
- .inspect(this::checkSomething)
+ .inspect(this::checkHasCompanionClass)
+ .inspect(this::checkHasLambdaClass)
.writeToZip();
if (parameters.getRuntime().isCf()) {
- // Run on the JVM
+ // Run on the JVM.
testForJvm()
.addProgramFiles(jar)
.run(parameters.getRuntime(), TestClass.class)
@@ -71,8 +64,8 @@
// Convert to DEX without desugaring.
testForD8()
.addProgramFiles(jar)
- .setEnableDesugaring(false)
.setMinApi(parameters.getApiLevel())
+ .setEnableDesugaring(false)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello, world!", "I::foo");
}
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
new file mode 100644
index 0000000..0fd267d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileInputCfVersion.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, 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;
+
+import static org.objectweb.asm.Opcodes.V1_4;
+import static org.objectweb.asm.Opcodes.V1_5;
+import static org.objectweb.asm.Opcodes.V1_6;
+import static org.objectweb.asm.Opcodes.V1_7;
+import static org.objectweb.asm.Opcodes.V1_8;
+import static org.objectweb.asm.Opcodes.V9;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.util.List;
+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 DesugarToClassFileInputCfVersion extends TestBase {
+
+ @Parameters(name = "{0}, input Cf version: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ ImmutableList.of(V1_4, V1_5, V1_6, V1_7, V1_8, V9));
+ }
+
+ private final TestParameters parameters;
+ private final int cfVersion;
+
+ public DesugarToClassFileInputCfVersion(TestParameters parameters, int cfVersion) {
+ this.parameters = parameters;
+ this.cfVersion = cfVersion;
+ }
+
+ @Test
+ public void test() throws Exception {
+ // Use D8 to desugar with Java classfile output.
+ Path jar =
+ testForD8(Backend.CF)
+ .addProgramClassFileData(transformer(TestClass.class).setVersion(cfVersion).transform())
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ if (parameters.getRuntime().isCf()) {
+ // Run on the JVM given that Cf version is supported.
+ if (cfVersion <= parameters.getRuntime().asCf().getVm().getClassfileVersion()) {
+ testForJvm()
+ .addProgramFiles(jar)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello, world!");
+ } else {
+ testForJvm()
+ .addProgramFiles(jar)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class);
+ }
+ } else {
+ assert parameters.getRuntime().isDex();
+ // Convert to DEX without desugaring.
+ testForD8()
+ .addProgramFiles(jar)
+ .setMinApi(parameters.getApiLevel())
+ .setEnableDesugaring(false)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello, world!");
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ if (System.currentTimeMillis() > 0) {
+ System.out.println("Hello, world!");
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
new file mode 100644
index 0000000..5dac547
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -0,0 +1,128 @@
+// Copyright (c) 2020, 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.backports;
+
+import static org.hamcrest.core.StringContains.containsString;
+
+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.utils.AndroidApiLevel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class ApiLevelBackportsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesStartingFromIncluding(Version.V9_0_0).build();
+ }
+
+ public ApiLevelBackportsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void backportSucceedsOnSupportedApiLevel() throws Exception {
+ testForD8()
+ .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt())
+ .setMinApi(AndroidApiLevel.B)
+ .run(parameters.getRuntime(), "Test")
+ .assertSuccessWithOutputLines("4");
+ }
+
+ @Test
+ public void warningForNonPlatformBuild() throws Exception {
+ testForD8()
+ .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt())
+ .setMinApi(30)
+ .compile()
+ .assertOnlyWarnings()
+ .assertWarningMessageThatMatches(
+ containsString("An API level of 30 is not supported by this compiler"))
+ .run(parameters.getRuntime(), "Test")
+ .assertFailureWithErrorThatMatches(
+ containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+ }
+
+ @Test
+ public void noWarningForPlatformBuild() throws Exception {
+ testForD8()
+ .addProgramClassFileData(Dump.mainWithMathMultiplyExactLongInt())
+ .setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild)
+ .run(parameters.getRuntime(), "Test")
+ .assertFailureWithErrorThatMatches(
+ containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
+ }
+
+ static class Dump implements Opcodes {
+
+ // Code for:
+ //
+ // class Test {
+ // public static void main(String[] args) {
+ // // Call Math.multiplyExact(long, int), which is not in Android Q.
+ // System.out.println(Math.multiplyExact(2L, 2));
+ // }
+ // }
+ //
+ static byte[] mainWithMathMultiplyExactLongInt() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(V1_8, ACC_SUPER, "Test", null, "java/lang/Object", null);
+
+ classWriter.visitSource("Test.java", null);
+
+ {
+ methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ Label label0 = new Label();
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitLineNumber(1, label0);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ Label label0 = new Label();
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitLineNumber(3, label0);
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitLdcInsn(Long.valueOf(2L));
+ methodVisitor.visitLdcInsn(Integer.valueOf(2));
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC, "java/lang/Math", "multiplyExact", "(JI)J", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(J)V", false);
+ Label label1 = new Label();
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitLineNumber(4, label1);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(5, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/NoBackportForAndroidPlatform.java b/src/test/java/com/android/tools/r8/desugar/backports/NoBackportForAndroidPlatform.java
deleted file mode 100644
index 47081ab..0000000
--- a/src/test/java/com/android/tools/r8/desugar/backports/NoBackportForAndroidPlatform.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2020, 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.backports;
-
-import static org.hamcrest.core.StringContains.containsString;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-@RunWith(Parameterized.class)
-public class NoBackportForAndroidPlatform extends TestBase implements Opcodes {
-
- private final TestParameters parameters;
-
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- // The use of high API level will produce dex files with high DEX version, so only run on high
- // API level VMs.
- return getTestParameters()
- .withDexRuntimes()
- .withApiLevelsStartingAtIncluding(AndroidApiLevel.P)
- .build();
- }
-
- public NoBackportForAndroidPlatform(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- @Test
- public void backportSucceedsOnSupportedApiLevel() throws Exception {
- testForD8()
- .addProgramClassFileData(mainWithMathMultiplyExactLongInt())
- .setMinApi(AndroidApiLevel.B)
- .run(parameters.getRuntime(), "Test")
- .assertSuccessWithOutputLines("4");
- }
-
- @Test
- public void warningForNonPlatformBuild() throws Exception {
- testForD8()
- .addProgramClassFileData(mainWithMathMultiplyExactLongInt())
- .setMinApi(30)
- .compile()
- .assertOnlyWarnings()
- .assertWarningMessageThatMatches(
- containsString("An API level of 30 is not supported by this compiler"))
- .run(parameters.getRuntime(), "Test")
- .assertFailureWithErrorThatMatches(
- containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
- }
-
- @Test
- public void noWarningForPlatformBuild() throws Exception {
- testForD8()
- .addProgramClassFileData(mainWithMathMultiplyExactLongInt())
- .setMinApi(AndroidApiLevel.magicApiLevelUsedByAndroidPlatformBuild)
- .run(parameters.getRuntime(), "Test")
- .assertFailureWithErrorThatMatches(
- containsString("java.lang.NoSuchMethodError: No static method multiplyExact(JI)J"));
- }
-
- // Code for:
- //
- // class Test {
- // public static void main(String[] args) {
- // // Call Math.multiplyExact(long, int), which is not in Android Q.
- // System.out.println(Math.multiplyExact(2L, 2));
- // }
- // }
- //
- private byte[] mainWithMathMultiplyExactLongInt() {
-
- ClassWriter classWriter = new ClassWriter(0);
- MethodVisitor methodVisitor;
-
- classWriter.visit(V1_8, ACC_SUPER, "Test", null, "java/lang/Object", null);
-
- classWriter.visitSource("Test.java", null);
-
- {
- methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
- methodVisitor.visitCode();
- Label label0 = new Label();
- methodVisitor.visitLabel(label0);
- methodVisitor.visitLineNumber(1, label0);
- methodVisitor.visitVarInsn(ALOAD, 0);
- methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
- methodVisitor.visitInsn(RETURN);
- methodVisitor.visitMaxs(1, 1);
- methodVisitor.visitEnd();
- }
- {
- methodVisitor =
- classWriter.visitMethod(
- ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
- methodVisitor.visitCode();
- Label label0 = new Label();
- methodVisitor.visitLabel(label0);
- methodVisitor.visitLineNumber(3, label0);
- methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
- methodVisitor.visitLdcInsn(Long.valueOf(2L));
- methodVisitor.visitLdcInsn(Integer.valueOf(2));
- methodVisitor.visitMethodInsn(
- INVOKESTATIC, "java/lang/Math", "multiplyExact", "(JI)J", false);
- methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(J)V", false);
- Label label1 = new Label();
- methodVisitor.visitLabel(label1);
- methodVisitor.visitLineNumber(4, label1);
- methodVisitor.visitInsn(RETURN);
- methodVisitor.visitMaxs(5, 1);
- methodVisitor.visitEnd();
- }
- classWriter.visitEnd();
-
- return classWriter.toByteArray();
- }
-}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
index bf823d4..6177bf3 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -19,10 +19,10 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
-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.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
@@ -89,10 +89,11 @@
DexProgramClass clazz = appView.appInfo().classes().iterator().next();
assertEquals(TestClass.class.getTypeName(), clazz.type.toSourceString());
- for (DexEncodedMethod method : clazz.methods()) {
- IRCode code = method.buildIR(appView, Origin.unknown());
- fieldAccessAnalysis.recordFieldAccesses(code, feedback, new MethodProcessorMock());
- }
+ clazz.forEachProgramMethod(
+ method -> {
+ IRCode code = method.buildIR(appView);
+ fieldAccessAnalysis.recordFieldAccesses(code, feedback, new MethodProcessorMock());
+ });
int bitsReadInBitField = feedback.bitsReadPerField.getInt(uniqueFieldByName(clazz, "bitField"));
assertTrue(BitUtils.isBitSet(bitsReadInBitField, 1));
@@ -216,12 +217,12 @@
}
@Override
- public boolean shouldApplyCodeRewritings(DexEncodedMethod method) {
+ public boolean shouldApplyCodeRewritings(ProgramMethod method) {
return false;
}
@Override
- public boolean isProcessedConcurrently(DexEncodedMethod method) {
+ public boolean isProcessedConcurrently(ProgramMethod method) {
return false;
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
index 7b7036f..2d56233 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
@@ -4,30 +4,59 @@
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
+import com.android.tools.r8.origin.SynthesizedOrigin;
+import java.util.Collections;
class CallGraphTestBase extends TestBase {
+
private DexItemFactory dexItemFactory = new DexItemFactory();
+ private DexProgramClass clazz =
+ new DexProgramClass(
+ dexItemFactory.createType("LCallGraphTest;"),
+ null,
+ new SynthesizedOrigin("test", CallGraphTestBase.class),
+ ClassAccessFlags.fromSharedAccessFlags(0),
+ dexItemFactory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ false,
+ DexProgramClass::invalidChecksumRequest);
Node createNode(String methodName) {
DexMethod signature =
dexItemFactory.createMethod(
- dexItemFactory.objectType,
- dexItemFactory.createProto(dexItemFactory.voidType),
- methodName);
- return new Node(
- new DexEncodedMethod(
- signature, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null));
+ clazz.type, dexItemFactory.createProto(dexItemFactory.voidType), methodName);
+ ProgramMethod method =
+ new ProgramMethod(
+ clazz,
+ new DexEncodedMethod(
+ signature, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null));
+ return new Node(method);
}
Node createForceInlinedNode(String methodName) {
Node node = createNode(methodName);
- node.method.getMutableOptimizationInfo().markForceInline();
+ node.getMethod().getMutableOptimizationInfo().markForceInline();
return node;
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/CycleEliminationTest.java b/src/test/java/com/android/tools/r8/ir/conversion/CycleEliminationTest.java
index c9ae9fd..2611dcd 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/CycleEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/CycleEliminationTest.java
@@ -161,9 +161,9 @@
for (Node node : configuration.nodes) {
if (configuration.forceInline.contains(node)) {
- node.method.getMutableOptimizationInfo().markForceInline();
+ node.getMethod().getMutableOptimizationInfo().markForceInline();
} else {
- node.method.getMutableOptimizationInfo().unsetForceInline();
+ node.getMethod().getMutableOptimizationInfo().unsetForceInline();
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/NodeExtractionTest.java b/src/test/java/com/android/tools/r8/ir/conversion/NodeExtractionTest.java
index 4088693..1459b20 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/NodeExtractionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/NodeExtractionTest.java
@@ -47,20 +47,20 @@
nodes.add(n6);
CallGraph cg = new CallGraph(nodes);
- Set<DexEncodedMethod> wave = cg.extractLeaves();
+ Set<DexEncodedMethod> wave = cg.extractLeaves().toDefinitionSet();
assertEquals(3, wave.size());
- assertThat(wave, hasItem(n3.method));
- assertThat(wave, hasItem(n4.method));
- assertThat(wave, hasItem(n6.method));
+ assertThat(wave, hasItem(n3.getMethod()));
+ assertThat(wave, hasItem(n4.getMethod()));
+ assertThat(wave, hasItem(n6.getMethod()));
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n2.method));
- assertThat(wave, hasItem(n5.method));
+ assertThat(wave, hasItem(n2.getMethod()));
+ assertThat(wave, hasItem(n5.getMethod()));
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(1, wave.size());
- assertThat(wave, hasItem(n1.method));
+ assertThat(wave, hasItem(n1.getMethod()));
assertTrue(nodes.isEmpty());
}
@@ -91,27 +91,27 @@
nodes.add(n6);
n1.addCallerConcurrently(n3);
- n3.method.getMutableOptimizationInfo().markForceInline();
+ n3.getMethod().getMutableOptimizationInfo().markForceInline();
CycleEliminator cycleEliminator = new CycleEliminator();
assertEquals(1, cycleEliminator.breakCycles(nodes).numberOfRemovedCallEdges());
CallGraph cg = new CallGraph(nodes);
- Set<DexEncodedMethod> wave = cg.extractLeaves();
+ Set<DexEncodedMethod> wave = cg.extractLeaves().toDefinitionSet();
assertEquals(3, wave.size());
- assertThat(wave, hasItem(n3.method));
- assertThat(wave, hasItem(n4.method));
- assertThat(wave, hasItem(n6.method));
+ assertThat(wave, hasItem(n3.getMethod()));
+ assertThat(wave, hasItem(n4.getMethod()));
+ assertThat(wave, hasItem(n6.getMethod()));
wave.clear();
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n2.method));
- assertThat(wave, hasItem(n5.method));
+ assertThat(wave, hasItem(n2.getMethod()));
+ assertThat(wave, hasItem(n5.getMethod()));
wave.clear();
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(1, wave.size());
- assertThat(wave, hasItem(n1.method));
+ assertThat(wave, hasItem(n1.getMethod()));
assertTrue(nodes.isEmpty());
}
@@ -142,20 +142,20 @@
nodes.add(n6);
CallGraph callGraph = new CallGraph(nodes, null);
- Set<DexEncodedMethod> wave = callGraph.extractRoots();
+ Set<DexEncodedMethod> wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n1.method));
- assertThat(wave, hasItem(n5.method));
+ assertThat(wave, hasItem(n1.getMethod()));
+ assertThat(wave, hasItem(n5.getMethod()));
- wave = callGraph.extractRoots();
+ wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n2.method));
- assertThat(wave, hasItem(n6.method));
+ assertThat(wave, hasItem(n2.getMethod()));
+ assertThat(wave, hasItem(n6.getMethod()));
- wave = callGraph.extractRoots();
+ wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n3.method));
- assertThat(wave, hasItem(n4.method));
+ assertThat(wave, hasItem(n3.getMethod()));
+ assertThat(wave, hasItem(n4.getMethod()));
assertTrue(nodes.isEmpty());
}
@@ -186,25 +186,25 @@
nodes.add(n6);
n1.addCallerConcurrently(n3);
- n3.method.getMutableOptimizationInfo().markForceInline();
+ n3.getMethod().getMutableOptimizationInfo().markForceInline();
CycleEliminator cycleEliminator = new CycleEliminator();
assertEquals(1, cycleEliminator.breakCycles(nodes).numberOfRemovedCallEdges());
CallGraph callGraph = new CallGraph(nodes, null);
- Set<DexEncodedMethod> wave = callGraph.extractRoots();
+ Set<DexEncodedMethod> wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n1.method));
- assertThat(wave, hasItem(n5.method));
+ assertThat(wave, hasItem(n1.getMethod()));
+ assertThat(wave, hasItem(n5.getMethod()));
- wave = callGraph.extractRoots();
+ wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n2.method));
- assertThat(wave, hasItem(n6.method));
+ assertThat(wave, hasItem(n2.getMethod()));
+ assertThat(wave, hasItem(n6.getMethod()));
- wave = callGraph.extractRoots();
+ wave = callGraph.extractRoots().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(n3.method));
- assertThat(wave, hasItem(n4.method));
+ assertThat(wave, hasItem(n3.getMethod()));
+ assertThat(wave, hasItem(n4.getMethod()));
assertTrue(nodes.isEmpty());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
index 1ea4e67..c838a0d 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
@@ -11,8 +11,9 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
@@ -21,8 +22,8 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -66,37 +67,41 @@
assertNotNull(m5);
assertNotNull(m6);
- Set<DexEncodedMethod> wave = cg.extractLeaves();
+ Set<DexEncodedMethod> wave = cg.extractLeaves().toDefinitionSet();
assertEquals(4, wave.size()); // including <init>
- assertThat(wave, hasItem(m3.method));
- assertThat(wave, hasItem(m4.method));
- assertThat(wave, hasItem(m6.method));
+ assertThat(wave, hasItem(m3.getMethod()));
+ assertThat(wave, hasItem(m4.getMethod()));
+ assertThat(wave, hasItem(m6.getMethod()));
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(2, wave.size());
- assertThat(wave, hasItem(m2.method));
- assertThat(wave, hasItem(m5.method));
+ assertThat(wave, hasItem(m2.getMethod()));
+ assertThat(wave, hasItem(m5.getMethod()));
- wave = cg.extractLeaves();
+ wave = cg.extractLeaves().toDefinitionSet();
assertEquals(1, wave.size());
- assertThat(wave, hasItem(m1.method));
+ assertThat(wave, hasItem(m1.getMethod()));
assertTrue(cg.nodes.isEmpty());
}
@Test
public void testPartialGraph() throws Exception {
- DexEncodedMethod em1 = findMethod("m1");
- DexEncodedMethod em2 = findMethod("m2");
- DexEncodedMethod em4 = findMethod("m4");
- DexEncodedMethod em5 = findMethod("m5");
+ ProgramMethod em1 = findMethod("m1");
+ ProgramMethod em2 = findMethod("m2");
+ ProgramMethod em4 = findMethod("m4");
+ ProgramMethod em5 = findMethod("m5");
assertNotNull(em1);
assertNotNull(em2);
assertNotNull(em4);
assertNotNull(em5);
+ ProgramMethodSet seeds = ProgramMethodSet.create();
+ seeds.add(em1);
+ seeds.add(em2);
+ seeds.add(em4);
+ seeds.add(em5);
CallGraph pg =
- new PartialCallGraphBuilder(appView, ImmutableSet.of(em1, em2, em4, em5))
- .build(executorService, Timing.empty());
+ new PartialCallGraphBuilder(appView, seeds).build(executorService, Timing.empty());
Node m1 = findNode(pg.nodes, "m1");
Node m2 = findNode(pg.nodes, "m2");
@@ -109,37 +114,37 @@
Set<DexEncodedMethod> wave = Sets.newIdentityHashSet();
- wave.addAll(pg.extractRoots());
+ wave.addAll(pg.extractRoots().toDefinitionSet());
assertEquals(2, wave.size());
- assertThat(wave, hasItem(m1.method));
- assertThat(wave, hasItem(m5.method));
+ assertThat(wave, hasItem(m1.getMethod()));
+ assertThat(wave, hasItem(m5.getMethod()));
wave.clear();
- wave.addAll(pg.extractRoots());
+ wave.addAll(pg.extractRoots().toDefinitionSet());
assertEquals(1, wave.size());
- assertThat(wave, hasItem(m2.method));
+ assertThat(wave, hasItem(m2.getMethod()));
wave.clear();
- wave.addAll(pg.extractRoots());
+ wave.addAll(pg.extractRoots().toDefinitionSet());
assertEquals(1, wave.size());
- assertThat(wave, hasItem(m4.method));
+ assertThat(wave, hasItem(m4.getMethod()));
assertTrue(pg.nodes.isEmpty());
}
private Node findNode(Iterable<Node> nodes, String name) {
for (Node n : nodes) {
- if (n.method.method.name.toString().equals(name)) {
+ if (n.getMethod().method.name.toString().equals(name)) {
return n;
}
}
return null;
}
- private DexEncodedMethod findMethod(String name) {
- for (DexClass clazz : appView.appInfo().classes()) {
+ private ProgramMethod findMethod(String name) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
for (DexEncodedMethod method : clazz.methods()) {
if (method.method.name.toString().equals(name)) {
- return method;
+ return new ProgramMethod(clazz, method);
}
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
index b5997bf..0c158b9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
@@ -7,7 +7,7 @@
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.ProgramMethod;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,11 +41,11 @@
.assertSuccessWithOutputLines("10");
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
// TODO(b/139246447): should avoid visiting A#<init>, which is trivial, default init!
- assert encodedMethod.holder().toSourceString().endsWith("A")
- && encodedMethod.toSourceString().contains("<init>")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
+ assert method.getHolderType().toSourceString().endsWith("A")
+ && method.toSourceString().contains("<init>")
+ : "Unexpected revisit: " + method.toSourceString();
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
index 54a3b8e..2edbb0b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
@@ -14,7 +14,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -60,11 +60,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
- if (encodedMethod.holder().toSourceString().endsWith("$C")) {
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
+ if (method.getHolderType().toSourceString().endsWith("$C")) {
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
} else {
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNull();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
index 96b85ec..e36941d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
@@ -14,7 +14,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -57,11 +57,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
- if (encodedMethod.holder().toSourceString().endsWith("$C")) {
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
+ if (method.getHolderType().toSourceString().endsWith("$C")) {
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
} else {
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNull();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
index 51797eb..8d405c4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/KeptMethodTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -55,8 +55,8 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert false : "Unexpected revisit: " + encodedMethod.toSourceString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert false : "Unexpected revisit: " + method.toSourceString();
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
index 19172e7..8a057dd 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/LibraryMethodOverridesTest.java
@@ -13,7 +13,7 @@
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.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -66,8 +66,8 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert false : "Unexpected revisit: " + encodedMethod.toSourceString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert false : "Unexpected revisit: " + method.toSourceString();
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
index 19a9034..2e76fa2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectNegativeTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -55,10 +55,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
assert callSiteOptimizationInfo.getAbstractArgumentValue(1).isUnknown();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
index 30aec5e..bdc3694 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeDirectPositiveTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.InternalOptions;
@@ -58,11 +58,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
- assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(1);
assert abstractValue.isSingleStringValue()
&& abstractValue.asSingleStringValue().getDexString().toString().equals("nul");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
index ba6b644..75dd8a8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -60,10 +60,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
assert callSiteOptimizationInfo.getAbstractArgumentValue(1).isUnknown();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
index a966e62..e837610 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfacePositiveTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.InternalOptions;
@@ -61,10 +61,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(1);
assert abstractValue.isSingleStringValue()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
index cacb6a3..df1fb98 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticNegativeTest.java
@@ -11,7 +11,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -52,10 +52,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(0).isDefinitelyNotNull();
assert callSiteOptimizationInfo.getAbstractArgumentValue(0).isUnknown();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
index 1d92c6e..a1e936b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeStaticPositiveTest.java
@@ -11,7 +11,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.InternalOptions;
@@ -55,10 +55,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(0).isDefinitelyNotNull();
AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(0);
assert abstractValue.isSingleStringValue()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
index 28523aa..3ae302a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -57,11 +57,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("m") || methodName.equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
if (methodName.equals("m")) {
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
assert callSiteOptimizationInfo.getAbstractArgumentValue(1).isUnknown();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 14ff937..30764845 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.InternalOptions;
@@ -59,13 +59,14 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
AbstractValue abstractValue = callSiteOptimizationInfo.getAbstractArgumentValue(1);
- if (encodedMethod.holder().toSourceString().endsWith("$A")) {
+ if (method.getHolderType().toSourceString().endsWith("$A")) {
assert abstractValue.isSingleStringValue()
&& abstractValue.asSingleStringValue().getDexString().toString().equals("nul");
} else {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
index 349c613..0cc9bb1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectNegativeTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -55,10 +55,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isDefinitelyNotNull();
assert upperBoundType.isClassType()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index 9119e88..e131be5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -57,11 +57,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("<init>") || methodName.equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType;
if (methodName.equals("test")) {
upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
index b341d62..4b4c534 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -60,10 +60,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isDefinitelyNotNull();
assert upperBoundType.isClassType()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
index 204f41b..bda0a3a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -60,13 +60,14 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isDefinitelyNotNull();
- if (encodedMethod.holder().toSourceString().endsWith("$A")) {
+ if (method.getHolderType().toSourceString().endsWith("$A")) {
assert upperBoundType.isClassType()
&& upperBoundType.asClassType().getClassType().toSourceString().endsWith("$Sub1");
} else {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
index d98e911..3c94778 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticNegativeTest.java
@@ -11,7 +11,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -52,10 +52,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(0);
assert upperBoundType.isDefinitelyNotNull();
assert upperBoundType.isClassType()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
index d014d5a..6ea0888 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -54,11 +54,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("<init>") || methodName.equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
// `arg` for `test` or the receiver of `Base#<init>`.
// TODO(b/139246447): should avoid visiting <init>, which is trivial, default init!
// For testing purpose, `Base` is not merged and kept. The system correctly caught that, when
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index c2fffc1..51145b2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -57,11 +57,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("m") || methodName.equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
if (methodName.equals("m")) {
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isDefinitelyNotNull();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index 22a4faa..8c17c3a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -57,11 +57,12 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("<init>") || methodName.equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType;
if (methodName.equals("m")) {
upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
index 5b79156..96614da 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectNegativeTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -53,8 +53,8 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert false : "Unexpected revisit: " + encodedMethod.toSourceString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert false : "Unexpected revisit: " + method.toSourceString();
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
index 9630bab..0b7ff7d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeDirectPositiveTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -54,10 +54,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
index e7c5597..79a49e0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -60,10 +60,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isNullable();
assert upperBoundType.isClassType()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
index 17cea42..27612a2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfacePositiveTest.java
@@ -12,7 +12,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -57,10 +57,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(1).isDefinitelyNotNull();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
index 1f3d6cc..0a18b69 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticNegativeTest.java
@@ -11,7 +11,7 @@
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.ProgramMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -50,8 +50,8 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert false : "Unexpected revisit: " + encodedMethod.toSourceString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert false : "Unexpected revisit: " + method.toSourceString();
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
index 4743089..700ec34 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeStaticPositiveTest.java
@@ -11,7 +11,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -51,10 +51,11 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("test")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
assert callSiteOptimizationInfo.getDynamicUpperBoundType(0).isDefinitelyNotNull();
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
index 4882c32..26bb65e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -57,16 +57,17 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- String methodName = encodedMethod.method.name.toString();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ String methodName = method.getReference().name.toString();
assert methodName.equals("m") || methodName.equals("test")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
if (methodName.equals("m")) {
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isNullable();
assert upperBoundType.isClassType()
- && upperBoundType.asClassType().getClassType().equals(encodedMethod.holder());
+ && upperBoundType.asClassType().getClassType().equals(method.getHolderType());
} else {
assert methodName.equals("test");
assert callSiteOptimizationInfo.getDynamicUpperBoundType(0).isDefinitelyNotNull();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
index 0009024..00601a9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
@@ -13,7 +13,7 @@
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.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -57,17 +57,18 @@
.inspect(this::inspect);
}
- private void callSiteOptimizationInfoInspect(DexEncodedMethod encodedMethod) {
- assert encodedMethod.method.name.toString().equals("m")
- : "Unexpected revisit: " + encodedMethod.toSourceString();
- CallSiteOptimizationInfo callSiteOptimizationInfo = encodedMethod.getCallSiteOptimizationInfo();
+ private void callSiteOptimizationInfoInspect(ProgramMethod method) {
+ assert method.getReference().name.toString().equals("m")
+ : "Unexpected revisit: " + method.toSourceString();
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ method.getDefinition().getCallSiteOptimizationInfo();
TypeElement upperBoundType = callSiteOptimizationInfo.getDynamicUpperBoundType(1);
assert upperBoundType.isClassType()
&& upperBoundType.asClassType().getClassType().toSourceString().endsWith("$A");
- if (encodedMethod.holder().toSourceString().endsWith("$A")) {
+ if (method.getHolderType().toSourceString().endsWith("$A")) {
assert upperBoundType.isDefinitelyNotNull();
} else {
- assert encodedMethod.holder().toSourceString().endsWith("$B");
+ assert method.getHolderType().toSourceString().endsWith("$B");
assert upperBoundType.isNullable();
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWithDefaultValueAssignmentAfterDefaultsOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWithDefaultValueAssignmentAfterDefaultsOptimizationTest.java
index df33e2b..8943139 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWithDefaultValueAssignmentAfterDefaultsOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWithDefaultValueAssignmentAfterDefaultsOptimizationTest.java
@@ -10,9 +10,8 @@
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 java.util.ArrayList;
-import java.util.Collection;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.Deque;
import java.util.Optional;
import org.junit.Test;
@@ -46,16 +45,16 @@
.assertSuccessWithOutputLines("42");
}
- private void waveModifier(Deque<Collection<DexEncodedMethod>> waves) {
- Collection<DexEncodedMethod> initialWave = waves.getFirst();
- Optional<DexEncodedMethod> printFieldMethod =
+ private void waveModifier(Deque<ProgramMethodSet> waves) {
+ ProgramMethodSet initialWave = waves.getFirst();
+ Optional<ProgramMethod> printFieldMethod =
initialWave.stream()
- .filter(method -> method.method.name.toSourceString().equals("printField"))
+ .filter(method -> method.getReference().name.toSourceString().equals("printField"))
.findFirst();
assertTrue(printFieldMethod.isPresent());
- initialWave.remove(printFieldMethod.get());
+ initialWave.remove(printFieldMethod.get().getDefinition());
- ArrayList<DexEncodedMethod> lastWave = new ArrayList<>();
+ ProgramMethodSet lastWave = ProgramMethodSet.create();
lastWave.add(printFieldMethod.get());
waves.addLast(lastWave);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
index d230621..b493f1d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
@@ -15,11 +15,10 @@
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.utils.IterableUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.util.Collection;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.function.Function;
import java.util.function.Predicate;
import org.junit.Test;
@@ -50,13 +49,12 @@
options -> {
options.testing.waveModifier =
(waves) -> {
- Function<String, Predicate<Collection<DexEncodedMethod>>> wavePredicate =
+ Function<String, Predicate<ProgramMethodSet>> wavePredicate =
methodName ->
wave ->
wave.stream()
.anyMatch(
- method ->
- method.method.toSourceString().contains(methodName));
+ method -> method.toSourceString().contains(methodName));
int readFieldsWaveIndex =
IterableUtils.firstIndexMatching(waves, wavePredicate.apply("readFields"));
assertTrue(readFieldsWaveIndex >= 0);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index fcb5958..32a0e6b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -77,13 +78,12 @@
assertEquals(originalHeader.getPackageName(), rewrittenHeader.getPackageName());
// We cannot assert equality of the data since it may be ordered differently. Instead we use
// the KotlinMetadataWriter.
- // TODO(b/155571455): Deactivating the method call to kotlinMetadataString until resolved.
- // String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
- // String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
- // // TODO(b/155534905): For invalid synthetic class lambdas, we emit null after rewriting.
- // if (clazzSubject.getKotlinClassMetadata().getHeader().getKind() != 3) {
- // assertEquals(expected, actual);
- // }
+ String expected = KotlinMetadataWriter.kotlinMetadataToString("", originalMetadata);
+ String actual = KotlinMetadataWriter.kotlinMetadataToString("", rewrittenMetadata);
+ // TODO(b/155534905): For invalid synthetic class lambdas, we emit null after rewriting.
+ if (clazzSubject.getKotlinClassMetadata().getHeader().getKind() != 3) {
+ assertEquals(expected, actual);
+ }
}
}
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 2b5270d..cacf66b 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -50,6 +50,7 @@
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Position;
@@ -83,6 +84,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -806,10 +808,31 @@
options.intermediate = intermediate;
DexItemFactory factory = options.itemFactory;
AppInfo appInfo = new AppInfo(DexApplication.builder(options, timing).build());
- DexApplication.Builder builder = DexApplication.builder(options, timing);
+ AppView<?> appView = AppView.createForR8(appInfo, options);
+ DexApplication.Builder<?> builder = DexApplication.builder(options, timing);
for (String clazz : classes) {
DexString desc = factory.createString(DescriptorUtils.javaTypeToDescriptor(clazz));
DexType type = factory.createType(desc);
+ DexProgramClass programClass =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin("test", MainDexListTests.class),
+ ClassAccessFlags.fromSharedAccessFlags(0),
+ factory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ false,
+ DexProgramClass::invalidChecksumRequest);
DexEncodedMethod[] directMethods = new DexEncodedMethod[methodCount];
for (int i = 0; i < methodCount; i++) {
MethodAccessFlags access = MethodAccessFlags.fromSharedAccessFlags(0, false);
@@ -831,32 +854,13 @@
DexAnnotationSet.empty(),
ParameterAnnotationsList.empty(),
code);
- AppView<?> appView = AppView.createForR8(appInfo, options);
- IRCode ir = code.buildIR(method, appView, Origin.unknown());
+ ProgramMethod programMethod = new ProgramMethod(programClass, method);
+ IRCode ir = code.buildIR(programMethod, appView, Origin.unknown());
RegisterAllocator allocator = new LinearScanRegisterAllocator(appView, ir);
method.setCode(ir, allocator, appView);
directMethods[i] = method;
}
- DexProgramClass programClass =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("test", MainDexListTests.class),
- ClassAccessFlags.fromSharedAccessFlags(0),
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- directMethods,
- DexEncodedMethod.EMPTY_ARRAY,
- false,
- DexProgramClass::invalidChecksumRequest);
+ programClass.getMethodCollection().addDirectMethods(Arrays.asList(directMethods));
builder.addProgramClass(programClass);
}
DirectMappedDexApplication application = builder.build().toDirect();
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorServiceLoaderTest.java b/src/test/java/com/android/tools/r8/relocator/RelocatorServiceLoaderTest.java
index 96d429c..759082f 100644
--- a/src/test/java/com/android/tools/r8/relocator/RelocatorServiceLoaderTest.java
+++ b/src/test/java/com/android/tools/r8/relocator/RelocatorServiceLoaderTest.java
@@ -48,7 +48,7 @@
public RelocatorServiceLoaderTest(TestParameters parameters) {}
@Test
- public void testNotRewritingServiceForNotFoundClass()
+ public void testRewritingOfServicesForNotFoundClasses()
throws IOException, CompilationFailedException, ResourceException {
File testJar = temp.newFile("test.jar");
Path testJarPath = testJar.toPath();
@@ -72,8 +72,13 @@
Reference.packageFromString("foo.bar"), Reference.packageFromString("baz.qux"))
.build());
zip = new ZipFile(relocatedJar.toFile());
- ZipEntry serviceEntry = zip.getEntry(SERVICE_FILE);
+ ZipEntry serviceEntry = zip.getEntry("META-INF/services/baz.qux.Baz");
assertNotNull(serviceEntry);
+ InputStream inputStream = zip.getInputStream(serviceEntry);
+ Scanner scanner = new Scanner(inputStream);
+ assertEquals("baz.qux.BazImpl", scanner.next());
+ assertEquals("foo.baz.OtherImpl", scanner.next());
+ assertFalse(scanner.hasNext());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java b/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
index 9690ea6..62d8695 100644
--- a/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
+++ b/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.BooleanUtils;
@@ -75,8 +76,15 @@
Map<String, String> mapping = new HashMap<>();
mapping.put(originalPrefix, newPrefix);
runRelocator(ToolHelper.R8_WITH_DEPS_JAR, mapping, output);
- inspectAllClassesRelocated(
- ToolHelper.R8_WITH_DEPS_JAR, output, originalPrefix, newPrefix + ".");
+ // TODO(b/155618698): Extend relocator with a richer language such that java.lang.Object is not
+ // relocated.
+ CompilationError compilationError =
+ assertThrows(
+ CompilationError.class,
+ () ->
+ inspectAllClassesRelocated(
+ ToolHelper.R8_WITH_DEPS_JAR, output, originalPrefix, newPrefix + "."));
+ assertThat(compilationError.getMessage(), containsString("must extend class java.lang.Object"));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
index 2d85c6b..17cce81 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -11,13 +11,12 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -78,10 +77,9 @@
DexApplication application =
new ApplicationReader(originalApplication, options, Timing.empty()).read();
- DexEncodedMethod method = getMethod(originalApplication, methodSig);
+ ProgramMethod method = getProgramMethod(originalApplication, methodSig);
// Get the IR pre-optimization.
- IRCode code =
- method.buildIR(AppView.createForD8(new AppInfo(application), options), Origin.unknown());
+ IRCode code = method.buildIR(AppView.createForD8(new AppInfo(application), options));
// Find the exit block and assert that the value is a phi merging the exceptional edge
// with the normal edge.
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 36c7766..8ef02dc 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -165,6 +166,10 @@
return getMethodSubject(application, signature).getMethod();
}
+ protected ProgramMethod getProgramMethod(AndroidApp application, MethodSignature signature) {
+ return getMethodSubject(application, signature).getProgramMethod();
+ }
+
/**
* Create an application with one method, and processed that application using R8.
*
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 e08c9b7..ed7ac4d 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
@@ -6,6 +6,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
@@ -94,6 +95,11 @@
}
@Override
+ public ProgramMethod getProgramMethod() {
+ return null;
+ }
+
+ @Override
public MethodSignature getOriginalSignature() {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 00d00ca..df3f287 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -35,7 +35,8 @@
private final DexClass dexClass;
final ClassNamingForNameMapper naming;
- FoundClassSubject(CodeInspector codeInspector, DexClass dexClass, ClassNamingForNameMapper naming) {
+ FoundClassSubject(
+ CodeInspector codeInspector, DexClass dexClass, ClassNamingForNameMapper naming) {
this.codeInspector = codeInspector;
this.dexClass = dexClass;
this.naming = naming;
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 782bbf0..0e504ca 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
@@ -25,11 +25,11 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.signature.GenericSignatureParser;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.InternalOptions;
@@ -60,13 +60,8 @@
@Override
public IRCode buildIR(InternalOptions options) {
options.programConsumer = DexIndexedConsumer.emptyConsumer();
- DexEncodedMethod method = getMethod();
- return method
- .getCode()
- .buildIR(
- method,
- AppView.createForD8(new AppInfo(codeInspector.application), options),
- Origin.unknown());
+ return getProgramMethod()
+ .buildIR(AppView.createForD8(new AppInfo(codeInspector.application), options));
}
@Override
@@ -145,6 +140,11 @@
}
@Override
+ public ProgramMethod getProgramMethod() {
+ return new ProgramMethod(clazz.getDexProgramClass(), getMethod());
+ }
+
+ @Override
public MethodSignature getOriginalSignature() {
MethodSignature signature = getFinalSignature();
if (clazz.naming == null) {
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 50911f3..b158404 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
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.InternalOptions;
@@ -54,6 +55,8 @@
public abstract DexEncodedMethod getMethod();
+ public abstract ProgramMethod getProgramMethod();
+
public Iterator<InstructionSubject> iterateInstructions() {
return null;
}
diff --git a/src/test/sampleApks/simple/res/values-da/strings.xml b/src/test/sampleApks/simple/res/values-da/strings.xml
new file mode 100644
index 0000000..26c62ec
--- /dev/null
+++ b/src/test/sampleApks/simple/res/values-da/strings.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, 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.
+-->
+<resources>
+ <string name="app_name">R8 simpel app</string>
+ <string name="referenced_from_layout">Tryk</string>
+ <!-- Do not inlcude referenced_from_code -->
+ <string name="not_used">ikke brugt</string>
+</resources>
diff --git a/tools/build_sample_apk.py b/tools/build_sample_apk.py
index c035520..a08a4ec 100755
--- a/tools/build_sample_apk.py
+++ b/tools/build_sample_apk.py
@@ -20,6 +20,7 @@
DEFAULT_AAPT = 'aapt' # Assume in path.
+DEFAULT_AAPT2 = 'aapt2' # Assume in path.
DEFAULT_D8 = os.path.join(utils.REPO_ROOT, 'tools', 'd8.py')
DEFAULT_DEXSPLITTER = os.path.join(utils.REPO_ROOT, 'tools', 'dexsplitter.py')
DEFAULT_JAVAC = jdk.GetJavacExecutable()
@@ -39,6 +40,9 @@
result.add_option('--aapt',
help='aapt executable to use',
default=DEFAULT_AAPT)
+ result.add_option('--aapt2',
+ help='aapt2 executable to use',
+ default=DEFAULT_AAPT2)
result.add_option('--api',
help='Android api level',
default=21,
@@ -50,6 +54,9 @@
result.add_option('--split',
help='Split the app using the split.spec file',
default=False, action='store_true')
+ result.add_option('--generate-proto-apk',
+ help='Use aapt2 to generate the proto version of the apk.',
+ default=False, action='store_true')
result.add_option('--install',
help='Install the app (including featuresplit)',
default=False, action='store_true')
@@ -273,6 +280,19 @@
if 'adb logcat' in output:
raise Exception('You have adb logcat running, please close it and rerun')
+def generate_proto_apks(apks, options):
+ proto_apks = []
+ for apk in apks:
+ proto_apk = apk + '.proto'
+ cmd = [options.aapt2, 'convert',
+ '-o', proto_apk,
+ '--output-format', 'proto',
+ apk]
+ utils.PrintCmd(cmd)
+ subprocess.check_call(cmd)
+ proto_apks.append(proto_apk)
+ return proto_apks
+
def Main():
(options, args) = parse_options()
apks = []
@@ -287,13 +307,11 @@
if is_split:
split(options.app)
dex_path = get_split_path(options.app, 'base')
-
temp_apk_path = create_temp_apk(options.app, '')
aapt_add_dex(options.aapt, dex_path, temp_apk_path)
apk_path = os.path.join(get_bin_path(options.app), '%s.apk' % options.app)
apk_utils.sign(temp_apk_path, apk_path, options.keystore)
apks.append(apk_path)
-
if is_split:
split_temp_apk_path = create_temp_apk(options.app, 'split_')
aapt_add_dex(options.aapt,
@@ -302,7 +320,9 @@
split_apk_path = os.path.join(get_bin_path(options.app), 'featuresplit.apk')
apk_utils.sign(temp_apk_path, split_apk_path, options.keystore)
apks.append(split_apk_path)
-
+ if options.generate_proto_apk:
+ proto_apks = generate_proto_apks(apks, options)
+ print('Generated proto apks available at: %s' % ' '.join(proto_apks))
print('Generated apks available at: %s' % ' '.join(apks))
if options.install or options.benchmark:
adb_install(apks)