blob: 201c2f91fd7c1a546ec5cebe77d36f561212c2af [file] [log] [blame]
// 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.shaking;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMember;
import com.android.tools.r8.shaking.KeepMemberInfo.Builder;
/** Immutable keep requirements for a member. */
@SuppressWarnings("BadImport")
public abstract class KeepMemberInfo<B extends Builder<B, K>, K extends KeepMemberInfo<B, K>>
extends KeepInfo<B, K> {
private final boolean allowValuePropagation;
protected KeepMemberInfo(B builder) {
super(builder);
this.allowValuePropagation = builder.isValuePropagationAllowed();
}
@SuppressWarnings("BadImport")
public boolean isKotlinMetadataRemovalAllowed(
DexProgramClass holder, GlobalKeepInfoConfiguration configuration) {
// Checking the holder for missing kotlin information relies on the holder being processed
// before members.
return holder.getKotlinInfo().isNoKotlinInformation() || !isPinned(configuration);
}
public boolean isValuePropagationAllowed(
AppView<AppInfoWithLiveness> appView, ProgramMember<?, ?> member) {
DexType type =
member.isField() ? member.asField().getType() : member.asMethod().getReturnType();
boolean isTypeInstantiated = !type.isAlwaysNull(appView);
return isValuePropagationAllowed(appView.options(), isTypeInstantiated);
}
public boolean isValuePropagationAllowed(
GlobalKeepInfoConfiguration configuration, boolean isTypeInstantiated) {
if (!isOptimizationAllowed(configuration) && isTypeInstantiated) {
return false;
}
return internalIsValuePropagationAllowed();
}
boolean internalIsValuePropagationAllowed() {
return allowValuePropagation;
}
public abstract static class Builder<B extends Builder<B, K>, K extends KeepMemberInfo<B, K>>
extends KeepInfo.Builder<B, K> {
private boolean allowValuePropagation;
protected Builder() {
super();
}
protected Builder(K original) {
super(original);
allowValuePropagation = original.internalIsValuePropagationAllowed();
}
// Value propagation.
public boolean isValuePropagationAllowed() {
return allowValuePropagation;
}
public B setAllowValuePropagation(boolean allowValuePropagation) {
this.allowValuePropagation = allowValuePropagation;
return self();
}
public B allowValuePropagation() {
return setAllowValuePropagation(true);
}
public B disallowValuePropagation() {
return setAllowValuePropagation(false);
}
@Override
boolean internalIsEqualTo(K other) {
return super.internalIsEqualTo(other)
&& isValuePropagationAllowed() == other.internalIsValuePropagationAllowed();
}
@Override
public B makeTop() {
return super.makeTop().disallowValuePropagation();
}
@Override
public B makeBottom() {
return super.makeBottom().allowValuePropagation();
}
}
public abstract static class Joiner<
J extends Joiner<J, B, K>, B extends Builder<B, K>, K extends KeepMemberInfo<B, K>>
extends KeepInfo.Joiner<J, B, K> {
protected Joiner(B builder) {
super(builder);
}
public J disallowValuePropagation() {
builder.disallowValuePropagation();
return self();
}
@Override
public Joiner<?, ?, ?> asMemberJoiner() {
return this;
}
@Override
public J merge(J joiner) {
// Should be extended to merge the fields of this class in case any are added.
return super.merge(joiner)
.applyIf(!joiner.builder.isValuePropagationAllowed(), Joiner::disallowValuePropagation);
}
}
}