blob: 6c598894790ae610236156418d4cec2cf2eefda3 [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.ir.optimize.info;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraint;
import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
import java.util.Set;
import java.util.function.Consumer;
public class MethodResolutionOptimizationInfo extends MethodOptimizationInfo {
private final AbstractValue abstractReturnValue;
private final DynamicType dynamicReturnType;
private final boolean mayHaveSideEffects;
private final boolean neverReturnsNormally;
private final BitSet nonNullParamOnNormalExits;
private final BitSet nonNullParamOrThrow;
private final int returnedArgument;
private final boolean returnValueOnlyDependsOnArguments;
MethodResolutionOptimizationInfo(
AbstractValue abstractReturnValue,
DynamicType dynamicReturnType,
boolean mayHaveSideEffects,
boolean neverReturnsNormally,
BitSet nonNullParamOnNormalExits,
BitSet nonNullParamOrThrow,
int returnedArgument,
boolean returnValueOnlyDependsOnArguments) {
this.abstractReturnValue = abstractReturnValue;
this.dynamicReturnType = dynamicReturnType;
this.mayHaveSideEffects = mayHaveSideEffects;
this.neverReturnsNormally = neverReturnsNormally;
this.nonNullParamOnNormalExits = nonNullParamOnNormalExits;
this.nonNullParamOrThrow = nonNullParamOrThrow;
this.returnedArgument = returnedArgument;
this.returnValueOnlyDependsOnArguments = returnValueOnlyDependsOnArguments;
}
static Builder builder() {
return new Builder();
}
static MethodOptimizationInfo create(MethodOptimizationInfo optimizationInfo) {
return builder()
.setAbstractReturnValue(optimizationInfo.getAbstractReturnValue())
.setDynamicReturnType(optimizationInfo.getDynamicType())
.setMayHaveSideEffects(optimizationInfo.mayHaveSideEffects())
.setNeverReturnsNormally(optimizationInfo.neverReturnsNormally())
.setNonNullParamOnNormalExits(optimizationInfo.getNonNullParamOnNormalExits())
.setNonNullParamOrThrow(optimizationInfo.getNonNullParamOrThrow())
.applyIf(
optimizationInfo.returnsArgument(),
builder -> builder.setReturnedArgument(optimizationInfo.getReturnedArgument()))
.setReturnValueOnlyDependsOnArguments(optimizationInfo.returnValueOnlyDependsOnArguments())
.build();
}
@Override
public boolean isMethodResolutionOptimizationInfo() {
return true;
}
@Override
public AbstractFunction getAbstractFunction() {
return AbstractFunction.unknown();
}
@Override
public AbstractValue getAbstractReturnValue() {
return abstractReturnValue;
}
@Override
public DynamicType getDynamicType() {
return dynamicReturnType;
}
@Override
public boolean mayHaveSideEffects() {
return mayHaveSideEffects;
}
@Override
public boolean mayHaveSideEffects(InvokeMethod invoke, InternalOptions options) {
return mayHaveSideEffects;
}
@Override
public boolean neverReturnsNormally() {
return neverReturnsNormally;
}
@Override
public BitSet getNonNullParamOnNormalExits() {
return nonNullParamOnNormalExits;
}
@Override
public BitSet getNonNullParamOrThrow() {
return nonNullParamOrThrow;
}
@Override
public boolean returnsArgument() {
return returnedArgument >= 0;
}
@Override
public int getReturnedArgument() {
return returnedArgument;
}
@Override
public boolean returnValueOnlyDependsOnArguments() {
return returnValueOnlyDependsOnArguments;
}
@Override
public boolean hasBeenInlinedIntoSingleCallSite() {
throw new Unreachable();
}
@Override
public MutableMethodOptimizationInfo toMutableOptimizationInfo() {
throw new Unreachable();
}
@Override
public boolean cannotBeKept() {
throw new Unreachable();
}
@Override
public boolean classInitializerMayBePostponed() {
throw new Unreachable();
}
@Override
public CallSiteOptimizationInfo getArgumentInfos() {
throw new Unreachable();
}
@Override
public ClassInlinerMethodConstraint getClassInlinerMethodConstraint() {
throw new Unreachable();
}
@Override
public EnumUnboxerMethodClassification getEnumUnboxerMethodClassification() {
throw new Unreachable();
}
@Override
public int getMaxRemovedAndroidLogLevel() {
throw new Unreachable();
}
@Override
public BridgeInfo getBridgeInfo() {
throw new Unreachable();
}
@Override
public Set<DexType> getInitializedClassesOnNormalExit() {
throw new Unreachable();
}
@Override
public InstanceInitializerInfo getContextInsensitiveInstanceInitializerInfo() {
throw new Unreachable();
}
@Override
public InstanceInitializerInfo getInstanceInitializerInfo(InvokeDirect invoke) {
throw new Unreachable();
}
@Override
public boolean isConvertCheckNotNull() {
throw new Unreachable();
}
@Override
public boolean isInitializerEnablingJavaVmAssertions() {
throw new Unreachable();
}
@Override
public SimpleInliningConstraint getNopInliningConstraint() {
throw new Unreachable();
}
@Override
public SimpleInliningConstraint getSimpleInliningConstraint() {
throw new Unreachable();
}
@Override
public boolean hasParametersWithBitwiseOperations() {
throw new Unreachable();
}
@Override
public BitSet getParametersWithBitwiseOperations() {
throw new Unreachable();
}
@Override
public BitSet getUnusedArguments() {
throw new Unreachable();
}
@Override
public boolean isMultiCallerMethod() {
throw new Unreachable();
}
@Override
public OptionalBool isReturnValueUsed() {
throw new Unreachable();
}
@Override
public boolean forceInline() {
throw new Unreachable();
}
@Override
public boolean returnValueHasBeenPropagated() {
throw new Unreachable();
}
static class Builder {
private AbstractValue abstractReturnValue = AbstractValue.unknown();
private DynamicType dynamicReturnType = DynamicType.unknown();
private boolean mayHaveSideEffects = true;
private boolean neverReturnsNormally = false;
private BitSet nonNullParamOnNormalExits = null;
private BitSet nonNullParamOrThrow = null;
private int returnedArgument = -1;
private boolean returnValueOnlyDependsOnArguments = false;
Builder applyIf(boolean condition, Consumer<Builder> fn) {
if (condition) {
fn.accept(this);
}
return this;
}
boolean isEffectivelyDefault() {
return dynamicReturnType.isUnknown()
&& abstractReturnValue.isUnknown()
&& returnedArgument < 0
&& nonNullParamOnNormalExits == null
&& nonNullParamOrThrow == null
&& mayHaveSideEffects
&& !neverReturnsNormally
&& !returnValueOnlyDependsOnArguments;
}
Builder setAbstractReturnValue(AbstractValue abstractReturnValue) {
this.abstractReturnValue = abstractReturnValue;
return this;
}
Builder setDynamicReturnType(DynamicType dynamicReturnType) {
this.dynamicReturnType = dynamicReturnType;
return this;
}
Builder setMayHaveSideEffects(boolean mayHaveSideEffects) {
this.mayHaveSideEffects = mayHaveSideEffects;
return this;
}
Builder setNeverReturnsNormally(boolean neverReturnsNormally) {
this.neverReturnsNormally = neverReturnsNormally;
return this;
}
Builder setNonNullParamOnNormalExits(BitSet nonNullParamOnNormalExits) {
this.nonNullParamOnNormalExits = nonNullParamOnNormalExits;
return this;
}
Builder setNonNullParamOrThrow(BitSet nonNullParamOrThrow) {
this.nonNullParamOrThrow = nonNullParamOrThrow;
return this;
}
Builder setReturnedArgument(int returnedArgument) {
this.returnedArgument = returnedArgument;
return this;
}
Builder setReturnValueOnlyDependsOnArguments(boolean returnValueOnlyDependsOnArguments) {
this.returnValueOnlyDependsOnArguments = returnValueOnlyDependsOnArguments;
return this;
}
MethodOptimizationInfo build() {
if (isEffectivelyDefault()) {
return DefaultMethodOptimizationInfo.getInstance();
}
return new MethodResolutionOptimizationInfo(
abstractReturnValue,
dynamicReturnType,
mayHaveSideEffects,
neverReturnsNormally,
nonNullParamOnNormalExits,
nonNullParamOrThrow,
returnedArgument,
returnValueOnlyDependsOnArguments);
}
}
}