blob: 395386dac57a2df358a26f60eab675fcd15cb60c [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.library.primitive;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.utils.StringUtils;
import java.util.Set;
public class BooleanMethodOptimizer extends PrimitiveMethodOptimizer {
BooleanMethodOptimizer(AppView<?> appView) {
super(appView);
}
@Override
DexMethod getBoxMethod() {
return dexItemFactory.booleanMembers.valueOf;
}
@Override
DexMethod getUnboxMethod() {
return dexItemFactory.booleanMembers.booleanValue;
}
@Override
boolean isMatchingSingleBoxedPrimitive(AbstractValue abstractValue) {
return abstractValue.isSingleBoxedBoolean();
}
@Override
public DexType getType() {
return dexItemFactory.boxedBooleanType;
}
@Override
public InstructionListIterator optimize(
IRCode code,
BasicBlockIterator blockIterator,
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
AffectedValues affectedValues,
Set<BasicBlock> blocksToRemove) {
if (singleTarget.getReference().isIdenticalTo(dexItemFactory.booleanMembers.parseBoolean)) {
optimizeParseBoolean(code, instructionIterator, invoke);
} else {
optimizeBoxingMethods(code, instructionIterator, invoke, singleTarget, affectedValues);
}
return instructionIterator;
}
private void optimizeParseBoolean(
IRCode code, InstructionListIterator instructionIterator, InvokeMethod invoke) {
Value argument = invoke.getFirstArgument().getAliasedValue();
if (argument.isDefinedByInstructionSatisfying(Instruction::isConstString)) {
ConstString constString = argument.getDefinition().asConstString();
if (!constString.instructionInstanceCanThrow(appView, code.context())) {
String value = StringUtils.toLowerCase(constString.getValue().toString());
if (value.equals("true")) {
instructionIterator.replaceCurrentInstructionWithConstInt(code, 1);
} else if (value.equals("false")) {
instructionIterator.replaceCurrentInstructionWithConstInt(code, 0);
}
}
}
}
@Override
void optimizeBoxMethod(
IRCode code,
InstructionListIterator instructionIterator,
InvokeMethod boxInvoke,
AffectedValues affectedValues) {
// Optimize Boolean.valueOf(b) into Boolean.FALSE or Boolean.TRUE.
Value argument = boxInvoke.getFirstOperand();
AbstractValue abstractValue = argument.getAbstractValue(appView, code.context());
if (abstractValue.isSingleNumberValue()) {
instructionIterator.replaceCurrentInstructionWithStaticGet(
appView,
code,
abstractValue.asSingleNumberValue().getBooleanValue()
? dexItemFactory.booleanMembers.TRUE
: dexItemFactory.booleanMembers.FALSE,
affectedValues);
return;
}
super.optimizeBoxMethod(code, instructionIterator, boxInvoke, affectedValues);
}
}