blob: fb0c944c4a9ded547f319ae6d84237a98b7ae5a2 [file] [log] [blame]
// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph.lens;
import com.android.tools.r8.graph.AppView;
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.ir.code.InvokeType;
import com.android.tools.r8.utils.Action;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
public abstract class NonIdentityGraphLens extends GraphLens {
private final DexItemFactory dexItemFactory;
private GraphLens previousLens;
private final Map<DexType, DexType> arrayTypeCache = new ConcurrentHashMap<>();
public NonIdentityGraphLens(AppView<?> appView) {
this(appView.dexItemFactory(), appView.graphLens());
}
public NonIdentityGraphLens(DexItemFactory dexItemFactory, GraphLens previousLens) {
this.dexItemFactory = dexItemFactory;
this.previousLens = previousLens;
}
public final DexItemFactory dexItemFactory() {
return dexItemFactory;
}
public final GraphLens getPrevious() {
return previousLens;
}
@SuppressWarnings("unchecked")
public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T find(
Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate) {
GraphLens current = this;
while (current.isNonIdentityLens()) {
com.android.tools.r8.graph.lens.NonIdentityGraphLens nonIdentityGraphLens =
current.asNonIdentityLens();
if (predicate.test(nonIdentityGraphLens)) {
return (T) nonIdentityGraphLens;
}
current = nonIdentityGraphLens.getPrevious();
}
return null;
}
@SuppressWarnings("unchecked")
public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T findPrevious(
Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate) {
GraphLens previous = getPrevious();
return previous.isNonIdentityLens() ? previous.asNonIdentityLens().find(predicate) : null;
}
public final <T extends com.android.tools.r8.graph.lens.NonIdentityGraphLens> T findPreviousUntil(
Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> predicate,
Predicate<com.android.tools.r8.graph.lens.NonIdentityGraphLens> stoppingCriterion) {
T found = findPrevious(predicate.or(stoppingCriterion));
return (found == null || stoppingCriterion.test(found)) ? null : found;
}
public final void withAlternativeParentLens(GraphLens lens, Action action) {
GraphLens oldParent = getPrevious();
previousLens = lens;
action.execute();
previousLens = oldParent;
}
@Override
public MethodLookupResult lookupMethod(
DexMethod method, DexMethod context, InvokeType type, GraphLens codeLens) {
if (method.getHolderType().isArrayType()) {
assert lookupType(method.getReturnType()) == method.getReturnType();
assert method.getParameters().stream()
.allMatch(parameterType -> lookupType(parameterType) == parameterType);
return MethodLookupResult.builder(this)
.setReference(method.withHolder(lookupType(method.getHolderType()), dexItemFactory))
.setType(type)
.build();
}
assert method.getHolderType().isClassType();
return internalLookupMethod(method, context, type, codeLens, result -> result);
}
@Override
public String lookupPackageName(String pkg) {
return getPrevious().lookupPackageName(pkg);
}
@Override
public final DexType lookupType(DexType type, GraphLens applied) {
if (this == applied) {
return type;
}
if (type.isPrimitiveType() || type.isVoidType() || type.isNullValueType()) {
return type;
}
if (type.isArrayType()) {
DexType result = arrayTypeCache.get(type);
if (result == null) {
DexType baseType = type.toBaseType(dexItemFactory);
DexType newType = lookupType(baseType);
result = baseType == newType ? type : type.replaceBaseType(newType, dexItemFactory);
arrayTypeCache.put(type, result);
}
return result;
}
return lookupClassType(type);
}
@Override
public final DexType lookupClassType(DexType type, GraphLens applied) {
assert type.isClassType() : "Expected class type, but was `" + type.toSourceString() + "`";
if (this == applied) {
return type;
}
return internalDescribeLookupClassType(getPrevious().lookupClassType(type));
}
@Override
protected FieldLookupResult internalLookupField(
DexField reference, GraphLens codeLens, LookupFieldContinuation continuation) {
if (this == codeLens) {
return getIdentityLens().internalLookupField(reference, codeLens, continuation);
}
return previousLens.internalLookupField(
reference,
codeLens,
previous -> continuation.lookupField(internalDescribeLookupField(previous)));
}
@Override
protected MethodLookupResult internalLookupMethod(
DexMethod reference,
DexMethod context,
InvokeType type,
GraphLens codeLens,
LookupMethodContinuation continuation) {
if (this == codeLens) {
GraphLens identityLens = getIdentityLens();
return identityLens.internalLookupMethod(
reference, context, type, identityLens, continuation);
}
return previousLens.internalLookupMethod(
reference,
getPreviousMethodSignature(context),
type,
codeLens,
previous -> continuation.lookupMethod(internalDescribeLookupMethod(previous, context)));
}
protected abstract FieldLookupResult internalDescribeLookupField(FieldLookupResult previous);
protected abstract MethodLookupResult internalDescribeLookupMethod(
MethodLookupResult previous, DexMethod context);
protected abstract DexType internalDescribeLookupClassType(DexType previous);
public abstract DexMethod getPreviousMethodSignature(DexMethod method);
/***
* The previous mapping for a method often coincides with the previous method signature, but it
* may not, for example for bridges inserted in vertically merged classes where the original
* signature is used for computing invoke-super but should not be used for mapping output.
*/
public DexMethod getPreviousMethodSignatureForMapping(DexMethod method) {
return getPreviousMethodSignature(method);
}
public abstract DexMethod getNextMethodSignature(DexMethod method);
@Override
public final boolean isIdentityLens() {
return false;
}
@Override
public final boolean isNonIdentityLens() {
return true;
}
@Override
public final com.android.tools.r8.graph.lens.NonIdentityGraphLens asNonIdentityLens() {
return this;
}
}