blob: 3dcd8722a9fe09ac6b145b43eb8f975125be90c6 [file] [log] [blame]
// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
import static com.android.tools.r8.graph.FieldResolutionResult.createSingleFieldResolutionResult;
import com.android.tools.r8.utils.SetUtils;
import java.util.Set;
/**
* Implements resolution of a field descriptor against a type.
*
* <p>See <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2">
* Section 5.4.3.2 of the JVM Spec</a>.
*/
public class FieldResolution {
private final DexDefinitionSupplier definitionFor;
public FieldResolution(DexDefinitionSupplier definitionFor) {
this.definitionFor = definitionFor;
}
public FieldResolutionResult resolveFieldOn(DexType type, DexField field) {
FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
definitionFor
.contextIndependentDefinitionForWithResolutionResult(type)
.forEachClassResolutionResult(
clazz -> builder.addResolutionResult(resolveFieldOn(clazz, field)));
return builder.buildOrIfEmpty(FieldResolutionResult.failure());
}
public FieldResolutionResult resolveFieldOn(DexClass holder, DexField field) {
assert holder != null;
return resolveFieldOn(holder, field, holder, SetUtils.newIdentityHashSet(8));
}
private FieldResolutionResult resolveFieldOn(
DexClass holder,
DexField field,
DexClass initialResolutionHolder,
Set<DexType> visitedInterfaces) {
assert holder != null;
// Step 1: Class declares the field.
DexEncodedField definition = holder.lookupField(field);
if (definition != null) {
return createSingleFieldResolutionResult(initialResolutionHolder, holder, definition);
}
// Step 2: Apply recursively to direct superinterfaces. First match succeeds.
FieldResolutionResult result =
resolveFieldOnDirectInterfaces(initialResolutionHolder, holder, field, visitedInterfaces);
if (result != null) {
return result;
}
// Step 3: Apply recursively to superclass.
if (holder.superType != null) {
FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
definitionFor
.contextIndependentDefinitionForWithResolutionResult(holder.superType)
.forEachClassResolutionResult(
superClass -> {
// Check if the subtype is a library type and if it is child of a non-library type.
// If that is the case, do not return any results.
if (holder.isLibraryClass() && !superClass.isLibraryClass()) {
return;
}
builder.addResolutionResult(
resolveFieldOn(superClass, field, initialResolutionHolder, visitedInterfaces));
});
return builder.buildOrIfEmpty(null);
}
return FieldResolutionResult.failure();
}
private FieldResolutionResult resolveFieldOnDirectInterfaces(
DexClass initialResolutionHolder,
DexClass clazz,
DexField field,
Set<DexType> visitedInterfaces) {
for (DexType interfaceType : clazz.interfaces.values) {
if (visitedInterfaces.add(interfaceType)) {
FieldResolutionResult.Builder builder = FieldResolutionResult.builder();
definitionFor
.contextIndependentDefinitionForWithResolutionResult(interfaceType)
.forEachClassResolutionResult(
ifaceClass -> {
// Check if the subtype is a library type and if it is child of a non-library
// type. If that is the case, do not return any results.
if (clazz.isLibraryClass() && !ifaceClass.isLibraryClass()) {
return;
}
builder.addResolutionResult(
resolveFieldOnInterface(
initialResolutionHolder, ifaceClass, field, visitedInterfaces));
});
FieldResolutionResult fieldResolutionResult = builder.buildOrIfEmpty(null);
if (fieldResolutionResult != null) {
return fieldResolutionResult;
}
}
}
return null;
}
private FieldResolutionResult resolveFieldOnInterface(
DexClass initialResolutionHolder,
DexClass interfaceClass,
DexField field,
Set<DexType> visitedInterfaces) {
// Step 1: Class declares the field.
DexEncodedField definition = interfaceClass.lookupField(field);
if (definition != null) {
return createSingleFieldResolutionResult(initialResolutionHolder, interfaceClass, definition);
}
// Step 2: Apply recursively to direct superinterfaces. First match succeeds.
return resolveFieldOnDirectInterfaces(
initialResolutionHolder, interfaceClass, field, visitedInterfaces);
}
}